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)以數值傳遞
指的是方法呼叫時,傳遞的參數是按值的拷貝傳遞。例如:
public class TempTest { private void test1(int a) { // 做点事情 a++; } public static void main(String args[]) { TempTest t = new TempTest(); int a = 3; t.test1(a);//这里传递的参数a就是按值传递。 System.out.printIn("main方法中的a===" + a); } }
按值傳遞的重要特點:傳遞的是值的拷貝,也就是說傳遞後就互不相關了。第9行的a和第2行的a是兩個變量,當改變第2行的a的值,第9行a的值是不變的,所以列印結果是3。
main 方法中的a 為3
test1 方法中的a 為4
我們將第9行的a稱為實參,第2行的a稱為形參;基本資料類型,形參資料的改變,不影響實參的資料。
2)依引用傳遞
指的是方法呼叫時,傳遞的參數是依照引用傳遞,其實傳遞的是所引用的位址,也就是變數所對應的記憶體空間的地址。
範例如下:
##
public class TempTest { private void test1(A a) { a.age = 20; System.out.printIn("test1方法中的age="+a.age); } public static void main(String args[]) { TempTest t = new TempTest(); A a = new A(); a.age = 10; t.test1(a);// 这里传递的参数a就是按引用传递 System.out.printIn("main方法中的age="+a.age); } } classA { public int age = 0; }運作結果如下:test1方法中的age = 20 main方法中的age = 20
與引用傳遞的重要特性:# 值的引用,也就是說傳遞前和傳遞後都指向同一個引用(也就是同一個記憶體空間)。
要正確理解依引用傳遞的過程,就必須學會理解記憶體分配的過程,記憶體分配示意圖可以輔助我們去理解這個過程。
用上面的範例來分析:
(1)、運作開始,執行第8行,創造了一個A的實例,記憶體分配示意圖如下:
main方法中的a
H
##(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行为新加的:
public class TempTest { private void test1(A a) { a = new A();// 新加的一行 a.age = 20; System.out.printIn("test1方法中的age="+a.age); } public static void main(String args[]) { TempTest t = new TempTest(); A a = new A(); a.age = 10; t.test1(a);// 这里传递的参数a就是按引用传递 System.out.printIn("main方法中的age="+a.age); } } classA { public int age = 0; }
运行结果为: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快车";
相关文章:
以上是解析java中的引用型別的概念的詳細內容。更多資訊請關注PHP中文網其他相關文章!