1. 程式人生 > >面向物件的基礎篇_02

面向物件的基礎篇_02

基礎篇_02的主要內容

  • 1、引用傳遞和值傳遞
  • 2、連結串列

一丶引用傳遞和值傳遞

1、基本型別和引用型別在記憶體中的儲存

|- Java中資料型別分為兩大類,【基本型別】和【物件型別】。

  • 基本型別的變數儲存原始值,即它代表的值就是數值本身;
    • 這裡的基本型別包括:byte,short,int,long,char,float,double,Boolean,returnAddress,etc...
  • 引用型別的變數儲存引用值。
    • "引用值"指向記憶體空間的地址,代表了某個物件的引用,而不是物件本身,物件本身存放在這個引用值所表示的地址的位置。
    • 引用型別包括:類型別,介面型別和陣列。

2、變數的基本型別和引用型別的區別

|- 變數也有兩種型別:【基本型別】和【引用型別】。

  • 基本資料型別在宣告時系統就給它分配空間:

    int a;
    a=10;//正確,因為宣告a時就分配了空間
  • 引用就不相同了,它宣告時只給變數分配了引用空間,而不分配資料空間:
Date date;
date=new Date();
date.getDate();
//執行例項化,開闢資料空間存放Date物件,然後把空間的首地址傳給“今天到的日期”變數  
System.out.println(date.getDate());//輸出今天的日期
/* *如果註釋掉date=new Date();就會有異常丟擲 *NullPointerException,意思就是說一個空的變數,一個空的棧記憶體。 *The local variable date may not have been initialized *也就是說物件的資料空間沒有分配 */

3、引用傳遞和值傳遞

引用傳遞是Java的核心問題,引用傳遞的操作的核心就是記憶體地址的傳遞。
這裡要用 【實際引數】 和 【形式引數】的概念來幫助理解,

  • 值傳遞:
    方法呼叫時,實際引數把它的值傳遞給對應的形式引數,函式接收的是原始值的一個copy,此時記憶體中存在兩個相等的基本型別,即實際引數和形式引數,後面方法中的操作都是對形參這個值的修改,不影響實際引數的值。


      • 範例:
              public class Test01 {
                    public static void change(int a){
                        a=10000;
                    }
                    public static void main(String[] args) {
                    int a=10;
                    System.out.println(a);//10
                    change(a);
                    System.out.println(a);//10
                    }
                }

橢圓是中a是實際引數,拷貝的a是形式引數
改變的是形式引數的值,結果不影響實際引數。

  • 引用傳遞:也稱為傳地址。
    方法呼叫時,實際引數的引用(地址,而不是引數的值)被傳遞給方法中相對應的形式引數,函式接收的是原始值的記憶體地址;在方法執行中,形參和實參內容相同,指向同一塊記憶體地址,方法執行中對引用的操作將會影響到實際物件。

      • 範例:
                public class Test02 {
                    public static void change(int []a){
                        a[0]=50;
                    }
                    public static void main(String[] args) {
                        int []a={10,20};
                        System.out.println(a[0]);//10
                        change(a);
                        System.out.println(a[0]);//50
                    }
                }

橢圓是中a是實際引數,拷貝的a是形式引數
這裡傳來的是地址,形式引數和實際引數有一樣的地址,改變了地址中的內容

  • 通過以下三個Demo來說明作用
class Demo{
    private int count = 10 ;
    public void setCount(int count){
    this.count = count ;
    }
    public int getCount(){
    return this.count ;
    }
};
public class Demo01 {
    public static void main(String args[]){
        Demo d1 = new Demo() ;
        d1.setCount(100) ;
        fun(d1) ;
        System.out.println(d1.getCount()) ;
        //輸出的結果為30
    }
    public static void fun(Demo d2){
        d2.setCount(30) ;
    }
};
public class Demo02 {
    public static void main(String args[]){
        String str = "hello" ;
            fun(str) ;
        System.out.println(str) ;
        //輸出的結果是hello
    }
    public static void fun(String temp){
        temp = "world" ;
    }
};
  • 字串的內容無法改變,改變的只是記憶體地址的指向。
class Demo{
    private String str = "hello" ;
    public void setStr(String str){
        this.str = str ;
        }
    public String getStr(){
        return this.str ;
    }
};
public class Demo03 {
    public static void main(String args[]){
        Demo d1 = new Demo() ;
        d1.setStr("world") ;
        fun(d1) ;
        System.out.println(d1.getStr()) ;
        //最後的輸出結果是!!!
    }
    public static void fun(Demo d2){
        d2.setStr("!!!") ;
    }
};

二丶連結串列的認識(這裡是說一個指標域的)

1、連結串列是一個個結點連線起來的長鏈。

  • 連結串列包括兩個部分
    • |-資料域:存放資料的區域。例如:姓名、地址、學號etc...
    • |-指標域:存放一個指標的區域。這個指標
class Node {
    private String name ; // 保留節點名稱
    private Node next ;   // 儲存下一個節點的引用
    public Node(String name){  //含有引數的構造器來儲存結點名稱
        this.name = name ;
        //this.name中的name是Node類中的name
        //= name 是傳過來引數name
    }
    public String getName(){
        return this.name ;
    }
    public void setNext(Node next){
        this.next = next ;
    }
    public Node getNext(){
        return this.next ;
    }
}
public class Demo04 {
    public static void main(String args[]){
        Node na = new Node("A") ;
        Node nb = new Node("B") ;
        Node nc = new Node("C") ;
            na.setNext(nb) ;//a的指標域指向b
            nb.setNext(nc) ;//b的指標域指向c
    }
}

在棧記憶體中存放的是na,nb,nc
在堆記憶體中存放的是name:A、B、C 和next:nb、nc、null

  • 第一個結點A的指標域na指向的是nb,所以堆記憶體中存放的是結點A到的name和nb。同理可得。
    在設定好了關係之後,只能通過遞迴的方式完成全部輸出。
public class Demo05 {
    public static void main(String args[]){
        Node na = new Node("車廂 A") ;
        Node nb = new Node("車廂 B") ;
        Node nc = new Node("車廂 C") ;
            na.setNext(nb) ;
            nb.setNext(nc) ;
            print(na) ;
    }
    public static void print(Node node){
        if(node != null){ // 避免空指向異常
            System.out.println(node.getName()) ;
            if(node.getNext() != null){
                print(node.getNext()) ;
            }
        }
    }
}

自動的完成增加和輸出的功能

  • 需要考慮到以下的幾個問題:
    • 每一個結點都要儲存起來。設定一個可以儲存節點關係的類:Node
    • 需要一個新增結點,並按照結點次序連線起來的類:Link
    • 第一個結點是頭結點,必須保留好根節點,private封裝起來

下面是一個連結串列的基本資料模型。

class Node {
    private String name ; // 保留節點名稱
    private Node next ;  // 儲存下一個節點的引用
    public Node(String name){
        this.name = name ;
    }
    public String getName(){
        return this.name ;
    }
    public void setNext(Node next){
        this.next = next ;
    }
    public Node getNext(){
        return this.next ;
    }
    public void addNode(Node newNode){//新增結點
        if(this.next == null){
            this.next = newNode ;
        } else {
            this.next.addNode(newNode) ;  // 當前節點的下一個繼續往下判斷
        }
    }
    public void printNode(){//輸出結點
        System.out.println(this.name) ;
        if(this.next != null){
            this.next.printNode() ;
        }
    }
}
class Link {  // 表示的是一個節點的操作類
    private Node root ;  // 表示根節點
    public void add(String name){  // 增加新節點
        Node newNode = new Node(name) ;  // 新節點
        if(this.root == null){  // 現在沒有根節點
            this.root = newNode ; // 第一個節點是根節點
        } else {  // 應該排在最後
            this.root.addNode(newNode) ;  // 向後面排隊
        }
    }
    public void print(){
        this.root.printNode() ;//從根結點開始呼叫,這個函式的方法在類Node中
    }
}
public class Test {
    public static void main(String args[]){
        Link link = new Link() ;
        link.add("車廂 A") ;
        link.add("車廂 B") ;
        link.add("車廂 C") ;
        link.add("車廂 D") ;
        link.add("車廂 E") ;
        link.print() ;
    }
}