眾所周知,Java存在8種基礎數(shù)據(jù)類型。
不過,Java字節(jié)碼中還有額外的兩種基礎數(shù)據(jù)類型,分別是reference type與returnAddress type。
想要學習Java 中的參數(shù)傳遞,就必須理解JVM是如何解釋基礎數(shù)據(jù)類型與引用數(shù)據(jù)類型的。
一切皆數(shù)據(jù)?一切皆對象?
我們先從最基礎的賦值開始:
Object A = new Object();
new Object() 做了什么?
JVM將在GC堆中開辟一定大小的空間用以存放此Object,此Object是引用數(shù)據(jù)類型(注意不是reference類型)。
Object A 做了什么?
JVM將在虛擬機棧中此線程棧開辟出一個slot用以存放A,注意此處A為reference type。(slot可以理解為用以存放基礎數(shù)據(jù)類型的線程私有的空間)
“ = ” 做了什么?
reference type 的A被賦值為先前new Object() 指令所產(chǎn)生的引用數(shù)據(jù)類型的一個對象。
案例分析
static String s1 = "abc" ;
public static void changeString(String s2){
s2="bcd";
}
changeString(s1);
運行以上代碼,s1改變了嗎?
答案是沒有。
為什么呢?
因為JVM中傳遞的不是reference本身,而是reference的拷貝。
或者你可以理解為傳遞的是一個int類型的數(shù)據(jù),不過這個int類型比較特殊,里面存放有一個對象的地址。
我們來一步一步分析上面的代碼:
String s1 = "abc";
//JVM開辟了一定大小的空間用以存放一個String對象,我們假設這個空間的起始值為0x8000。那么reference類型的s1就被賦值為0x8000。
void changeString(String s2){
//JVM中傳遞的是基礎數(shù)據(jù)類型reference ,此時開辟一個線程幀,為s2開辟一個slot,其值與s1相同,為0x8000
s2="bcd";
// 我們假設“bcd”的地址為0x9000,那么s2作為一個reference類型的數(shù)據(jù)將被賦值為0x9000
}
所以,函數(shù)changeString() 所做的只是新建了一個reference類型的數(shù)據(jù)s2,然后把“bcd”的地址賦值給了s2,對于s1和s1所指向的對象“abc”沒有做任何事,我們當然也看不到任何改變了。
綜上所述,JVM中傳遞的所有數(shù)據(jù)都是基礎數(shù)據(jù)類型的數(shù)據(jù),只是JVM會解析這是一個普通的數(shù)據(jù)類型還是 reference type 或 returnAddress type 。
所以,所有對形如s2這樣的傳入reference進行 = 的賦值,都不會改變s1的數(shù)據(jù),即s1依然會指向原來的對象。
用不太嚴謹?shù)脑拋碚f:Java中傳遞引用數(shù)據(jù)類型本質(zhì)是傳遞其地址的拷貝。
所以,才說Java中只有值傳遞。
不過,值傳遞與引用傳遞并不能完全區(qū)分來看,將引用數(shù)據(jù)類型看做是傳遞引用對于理解Java、日常編程并無不可。