不同於CPP,JAVA中不需要程序員對指針進行操作。不過,這不代表JAVA沒有指針,事實上,JAVA的指針操作都被底層代碼封裝了。筆者在初學Java時,雖然就了解了形參,實參,StringBuffer這些概念,但一直只流於表面,對此沒有一個深度的認識。直到最近開始學習JVM虛擬機,才真正認識到了JAVA的精妙之處。
首先,先說結論,Java中所有的基本數據類型的傳遞,都是按值傳遞,即傳遞的都是形參。除此以外的其他任何傳遞都是按地址傳遞,傳遞過去的都是實參,即cpp概念中的引用傳遞。最初筆者學習時也是就看到這,雖然知道了結論,但由於概念過於抽象,始終無法理解其本源(或者說內存模型中到底發生了什么)。Talk is cheap,show me the code。下面,我們來看一段代碼。
package point; public class Formal { private void formal(int p){ p=p*5; System.out.println(p); } public static void main(String[]args){ int i=5; Formal fromal=new Formal(); fromal.formal(i); System.out.println(i); } }
這段代碼在控制台輸出的結果是25和5,很顯然,按照正常的邏輯來說的話應該是25,25才對。為什么會出現這種結果?事實上,Java中對基本數據類型的傳遞都是值傳遞(不清楚為什么這樣,筆者的理解是基本數據類型在內存中的組合是有限的,這樣內存可以知道你需要傳遞的是什么,換而言之,它可以真正理解你要傳遞的東西,因此可以復制一份進行傳遞,這樣雖然會增大程序員的學習成本,但可以節省內存或者是增進效率。而非基本數據類型因為變化太多了,所以無法這么操作。不知道本人的理解有沒有誤差,才疏學淺,希望大神們多多指正)。通俗一點說,就是復制操作,在內存中,JVM只是把你操作的數據復制了一份給你傳遞到的對象,而不是把它本身傳遞了過去。
這里要說一個特例,String類,貼一段代碼。
package point; public class ActualString { private void actual(String color){ color=color+" is red"; System.out.println(color); } public static void main(String[]args){ String car="myCar"; ActualString actualString =new ActualString(); actualString.actual(car); System.out.println(car); } }
這里控制台輸出結果是myCar is red,myCar,這不代表String傳遞的也是形參,或者是String是基本數據類型,事實上因為String類都是被final關鍵字修飾的,所以它的值不會變化,所以,字符串拼接之類的操作事實上只是在內存中開辟了一個新的空間,而原有的空間其實還存在,所以這就是為什么字符串的操作要使用StringBuffer類。
下面我們看一下實參的代碼。
package point; public class Actual { private void actual(int arr[]){ arr[0]=arr[0]*5; System.out.println(arr[0]); } public static void main(String[]args){ int a[]=new int[]{5}; Actual actual=new Actual(); actual.actual(a); System.out.println(a[0]); } }
毫無疑問,這次控制台輸出的結果是25,25。這里傳遞的就是對象本身的地址值,即實參,可以理解為剪切操作,將自身傳遞過去。
package point; class Variable{ public static Variable VAR=null; public int i; protected void a(int p){ p=p*5; System.out.println(p); } public Variable(){ i=5; Variable.VAR=this; } } public class FormalInActual { public static void main(String[] args){ Variable variable=new Variable(); System.out.println(variable.i); variable.a(variable.VAR.i); System.out.println(variable.VAR.i); } }
輸出結果是5,25,5。即使是像這樣把基本數據類型寫進方法里,通過方法傳遞,其傳遞的依舊是形參。
