一、傳值和傳址(引用)
Java 的參數傳遞分爲傳遞基本數據類型(傳值)和傳遞引用數據類型(傳址)
public class Demo {
public void fun(Test test, int i) {
test.name = "test2";
i = 2;
System.out.println(i);
}
public static void main(String[] args) {
Demo demo = new Demo();
Test test = new Test();
int i = 1;
demo.fun(test, i);
System.out.print(test.name + " and " + i);
}
}
class Test {
String name = "test";
}
2
test2 and 1
對於基本數據類型,當我們修改傳遞的值,原來的值不會改變,所以傳遞的是值的拷貝。值的拷貝在一塊兒新的內存中。
對於引用數據類型,當我們通過傳遞的引用變量修改對象的屬性,原引用指向的對象也將改變,所以沒有將對象的數據拷貝傳遞,傳遞的是指向對象的引用變量,即對象的地址。當然,引用變量是值傳遞,引用變量的拷貝在一塊兒新的內存中。
正常來說,傳值更符合正常思路。我把值傳給你,你使用它,不會影響我的值。
因爲傳址的特點,可以將大數據存放到對象中,傳遞對象引用,減少參數(局部變量表)的大小以提高棧幀的空間利用率。
二、String 的參數傳遞
public class Demo {
String str = new String("hello");
char[] ch = {'a', 'b', 'c'};
public void fun(String str, char[] ch) {
str = "world";
ch[0] = 'd';
}
public static void main(String[] args) {
Demo demo = new Demo();
demo.fun(demo.str, demo.ch);
System.out.print(demo.str + " and ");
System.out.print(demo.ch);
}
}
hello and dbc
- 局部變量 str 和全局變量 str 這 2 個名稱相同變量,但內存位置不同的值都是 0x1001(假設)
- 對象 test 調用 fun 方法,將實參 test.str(全局變量 str 存放對象 "hello" 的內存地址)和 test.ch(全局變量 ch 存放字符數組對象的內存地址),傳給 fun 方法的形參 str 引用和 ch 引用。
- 局部變量 str 存放對象 "hello" 的內存地址。
"world"
匿名對象,str = "world";
等價於str = new String("world")
,相當於將在堆中重新分配一個內存空間存放 "world",局部變量 str 指向 "world"。局部變量 str 的生命週期和方法相同,只是名稱和全局變量 str 相同。
以上兩步操作在 JVM 中如下圖所示,內存地址爲假設。
- char ch[] 與 char[] ch 等價。語句
ch[0] = 'd';
將替換字符數組對象中下標爲 0 的字符,即改變了對象的內容。test.str 沒有改變,還是 "hello",test.ch 從 "abc" 改爲 "dbc"。
IDEA 調試圖如下:
2.1、理解引用存放地址
Book a == new Book();// 對象 1
Book b == new Book();// 對象 2
b = a;
問:那個對象會被回收? 答:對象 2,因爲將引用 a 中存放對象 1 的地址賦值給了引用 b,所以引用 b 將 “指向” 對象 1,對象 2 將被回收。
三、總結
可以將地址視爲值,所以傳值和傳址都可以視爲傳值。