經常看到有人說什麼值傳遞、引用傳遞,其實都是值傳遞,區別不過是傳的值的類型罷了。 傳值方式 java傳值有且只有一種方式,將參數的“值”複製後傳入,這個“值”是指變數名所對應的地址中存放的值,對於值類型和對象類型,由於地址中存放的東西不同,因此表現有所不同: 對於8種值類型,其存放的就是本身的值,因 ...
經常看到有人說什麼值傳遞、引用傳遞,其實都是值傳遞,區別不過是傳的值的類型罷了。
傳值方式
java傳值有且只有一種方式,將參數的“值”複製後傳入,這個“值”是指變數名所對應的地址中存放的值,對於值類型和對象類型,由於地址中存放的東西不同,因此表現有所不同:
- 對於8種值類型,其存放的就是本身的值,因此表現為將值傳遞到函數中,修改後的值對原值無影響。
- 對於對象來說,其存放的是對象頭,裡面包含了對象的類型、首地址等。將對象頭的值傳遞到函數中,其仍然能正確指向對象本身。
傳遞的是值的拷貝,而非其本身
值類型
對於值類型來說
7++;
這種無疑是錯誤的,因為不能對常量進行修改。任何一個IDE都會報錯。
但如果將其作為參數傳入
public class ObjTest {
public static void main(String[] args) {
inc(7);
}
private static void inc(int a) {
a++;
System.out.println(a);
}
}
那麼就不會報錯,並且輸出8
。這是因為在傳遞到函數裡面的並不是常量7
,而是一個拷貝int a = 7
,而a
是一個int
類型的變數,因此可以自增。
對象
而對於對象來說,同樣如此。
public class ObjTest {
public static void main(String[] args) {
inc(7);
Node n1 = new Node();
f1(n1);
System.out.println("n1 = " + n1);
}
private static void f1(Node node) {
node.a++;
node.b += 2;
node.c += 3;
node.d = new int[]{1, 5};
// 在此設置斷點2
node = new Node();
node.a = -1;
node.b = -2;
node.d[0] = 3;
System.out.println("node = " + node);
}
private static void inc(int a) {
a++;
System.out.println(a);
}
}
public class Node {
public int a;
public int b;
public int c;
public int[] d = new int[2];
}
在執行到斷點1的時候,如下圖所示,可以看到,n1
的所有值都為預設值,地址為0x704
在執行到斷點2(此行未執行)時,如下圖所示,可以看到,node
指向的地址仍為@704
,值已經進行了對應的修改
繼續執行到函數結束,可以看到node
指向了@708
,屬性的值變為了新的值。
結束子函數,回到主函數中,可以看到n1
的所有屬性都與node
指向@704
時相同
可見,同值類型的變數相同,傳入子函數的對象頭node
並不是主函數中的對象頭n1
本身,而是它的一個拷貝,他們指向同一個對象@704
,無論是通過n1
,還是初始的node
,都可以對@704
進行操作(調用方法,修改屬性),因而好像和值類型的傳遞有所不同。但如果修改node
本身的值,令其指向@708
,這對n1
沒有任何影響,n1
依然指向@704
。此後通過node
修改對象的值,修改的是@708
的值,與@704
沒有任何關係,因此也對主函數中的n1
沒有任何影響。
因此,所謂引用傳遞,不過是值是引用(或者說指針)的值傳遞。