1. 程式人生 > >java中的引用型別概念

java中的引用型別概念

此文章轉自:http://blog.sina.com.cn/s/blog_7fb1495b01012sfn.html

1、什麼是引用型別

引用型別(reference type)指向一個物件,不是原始值,指向物件的變數是引用變數。

在java裡面除去基本資料型別的其它型別都是引用資料型別,自己定義的class類都是引用型別,可以像基本型別一樣使用。

示例如下:
 public class MyDate {
        private int day = 8;
        private int month = 8;
        private int year = 2008
; private MyDate(int day, int month, int year){...} public void print(){...} } public class TestMyDate { public static void main(String args[]) { //這個today變數就是一個引用型別的變數 MyDate today = new MyDate(23, 7, 2008); } }

2、引用型別的賦值

在java程式語言中,用類的一個型別宣告的變數被指定為引用型別,這是因為它正在引用一個非原始型別,這對賦值具有重要的意義。如下程式碼:
    int x = 7;
    int y = x;
    String s = "Hello";
    String t = s;
四個變數被建立:兩個原始型別 int 和兩個引用型別String。x的值是7,而這個值被複制到y;x和y是兩個獨立的變數且其中任何一個的進一步的變化都不對另外一個構成影響。至於變數s和t,只有一個String物件存在,它包含了文字"Hello",s和t均引用這個單一個物件。


如果將變數t重新定義為t="World";則新的物件World被建立,而t引用這個物件。      

3、按值傳遞和按引用傳遞的區別

1)按值傳遞

指的是在方法呼叫時,傳遞的引數是按值的拷貝傳遞。示例如下:
1.    public class TempTest {
2.        private void test1(int a) {
3.            // 做點事情
4.            a++;
5.        }
6.       
7.        public static void main(String args[]) {
8.            TempTest t = new TempTest();
9.            int a = 3;
10.            t.test1(a);//這裡傳遞的引數a就是按值傳遞。
11.            System.out.printIn("main方法中的a===" + a);
12.         }
13.     }
按值傳遞的重要特點:傳遞的是值的拷貝,也就是說傳遞後就互不相關了。第9行的a和第2行的a是兩個變數,當改變第2行的a的值,第9行a的值是不變的,所以列印結果是3。

main  方法中的a 為 3
test1 方法中的a 為 4

我們把第9行的a稱之為實參,第2行的a稱之為形參;對於基本資料型別,形引數據的改變,不影響實參的資料。

2)按引用傳遞

指的是在方法呼叫時,傳遞的引數是按引用進行傳遞,其實傳遞的是引用的地址,也就是變數所對應的記憶體空間的地址。

示例如下:
1.    public class TempTest {
2.        private void test1(A a) {
3.            a.age = 20;
4.            System.out.printIn("test1方法中的age="+a.age);
5.        }
6.        public static void main(String args[]) {
7.            TempTest t = new TempTest();
8.            A a = new A();
9.            a.age = 10;
10.           t.test1(a);// 這裡傳遞的引數a就是按引用傳遞
11.              System.out.printIn("main方法中的age="+a.age);
12.         }
13.     }
14.     classA {
15.         public int age = 0;
16.     }  
執行結果如下:test1方法中的age = 20  main方法中的age = 20

**按引用傳遞的重要特點:**

傳遞的是值的引用,也就是說傳遞前和傳遞後都指向同一個引用(也就是同一個記憶體空間)。

要想正確理解按引用傳遞的過程,就必須學會理解記憶體分配的過程,記憶體分配示意圖可以輔助我們去理解這個過程。

用上面的例子來進行分析:

(1)、執行開始,執行第8行,建立了一個A的例項,記憶體分配示意圖如下:

  main方法中的a 

  

(2)、執行第9行,修改了A例項裡面的age的值,記憶體分配示意圖如下:   

  main方法中的a  

 

(3)、執行第10行,是把main方法中的變數a所引用的記憶體空間地址,按引用傳遞給test1方法中的a變數。請注意:這兩個a變數是完全不同的,不要被名稱相同所矇蔽,但它們指向了同一個A例項。記憶體分配示意圖如下:



(4)、執行第3行,為test1方法中的變數a指向A例項的age進行賦值,完成後形成新的記憶體示意圖如下:

 此時A例項的age值的變化是由test1方法引起的。

(5)、執行第4行,根據此時的記憶體示意圖,輸出test1方法中的age=20

(6)、執行第11行,根據此時的記憶體示意圖,輸出main方法中的age=20

3)對上述例子的改變

理解了上面的例子,可能有人會問,那麼能不能讓按照引用傳遞的值,相互不影響呢?就是test1方法裡面的修改不影響到main方法裡面的呢?

方法是在test1方法裡面新new一個例項就可以了。改變成下面的例子,其中第3行為新加的:
1.    public class TempTest {
2.        private void test1(A a) {
3.            a = new A();// 新加的一行
4.            a.age = 20;
5.            System.out.printIn("test1方法中的age="+a.age);
6.        }
7.        public static void main(String args[]) {
8.            TempTest t = new TempTest();
9.            A a = new A();
10.            a.age = 10;
11.           t.test1(a);// 這裡傳遞的引數a就是按引用傳遞
12.              System.out.printIn("main方法中的age="+a.age);
13.         }
14.     }
15.     classA {
16.         public int age = 0;
17.     }  
執行結果為:test1方法中的age=20  main方法中的age=10

實現了按引用傳遞的值傳遞前與傳遞後互不影響,還是使用記憶體示意圖來理解一下:

(1)、執行開始,執行第9行,建立了一個A例項,記憶體分配示意圖如下:



(2)、執行第10行,是修改A例項裡面的age的值,執行後記憶體分配示意圖如下:



(3)、執行第11行,是把mian方法中的變數a所引用的記憶體地址,按引用傳遞給test1方法中的a變數。請注意:這兩個a變數是完全不同的,不要被名稱相同所矇蔽。



 (4)、執行第3行,為test1方法中的變數a重新生成了新的A例項,完成後形成的新的記憶體示意圖如下:



 (5)、執行第4行,為test1方法中的變數a指向的新的A例項的age進行賦值,完成後形成新的記憶體示意圖如下:



注意:這個時候test1方法中的變數a的age被改變,而main方法中的a變數是沒有改變的。

 (6)、執行第5行,根據此時的記憶體示意圖,輸出test1方法中的age=20

 (7)、執行第12行,根據此時的記憶體示意圖,輸出main方法中的age=10

說明:

(1)、“在Java裡面引數傳遞都是按值傳遞”這句話的意思是:按值傳遞是傳遞的值的拷貝,按引用傳遞其實傳遞的是引用的地址值,所以統稱按值傳遞。

(2)、在Java裡面只有基本型別和按照下面這種定義方式的String是按值傳遞,其它的都是按引用傳遞。就是直接使用雙引號定義的字串方式:String str = "Java快車";