Java傳值和引用筆試題透析

Java傳值和引用筆試題透析

Java中函數傳值

對於基本類型而言,傳值就是把自己複製一份傳遞,及時自己的副本變了,自己不變。

對於對象類型而言,它的引用副本(類似與C++的指針)指向自己的地址,而不是自己實際值的副本。我們也可以這麼理解:所謂的引用副本相當於另外一個指向本指針對應對象地址的新指針。

Java傳值和引用筆試題透析

原因:對象本身比較大,採用重新複製對象值的辦法,浪費內存且速度慢。

我們來看幾個例子徹底幫助我們進行理解。

基本數據類型

Java傳值和引用筆試題透析

運行結果:

Java傳值和引用筆試題透析

boolean為基本類型,test =!test只改變了傳來的參數值對參數源變量本身沒有任何影響。

對象類型:StringBuffer為例

Java傳值和引用筆試題透析

運行結果:

Java傳值和引用筆試題透析

test(sb) 這裡sb作為參數傳入到函數里,在test函數里 sb只是一個引用,Java對於引用形式傳遞對象類型的變量時,實際上是將引用作為一個副本傳進方法中。

函數里對象副本指向的是什麼呢?

指向的是對象的地址,通過引用副本找到地址並修改地址中的值,因而外層的對象對應地址的值也被改變了。

對象類型:String為例

Java傳值和引用筆試題透析

運行結果:

Java傳值和引用筆試題透析

為什麼會這樣呢?難道和上面的原理不同?

str = "World"時,系統自動生成一個新的字符串對象,並把這個字符串對象賦值為“World”,然後再吧這個對象的引用給str。既然是新的對象(可以理解成 str = new String("World"),實際上應該是這個str指向字符串常量池中的world字符串,而且這裡的str只是main函數里面str的一個副本而已),它的變化就和原來的對象沒有關係,函數結束以後副本的str雖然指向了新的字符串"World”但是外層的str對象指向的還是之前的“Hello”。

而且我們看一下源碼,發現字符串是final類型的,是常量,創建以後其值是無法改變的(源碼註釋裡面也說的很清楚):

Java傳值和引用筆試題透析

Java傳值和引用筆試題透析

而上面例子中StringBuffer我們看一下源碼註釋:Java傳值和引用筆試題透析

StringBuffer是線程安全的,類似一個String,但是是可以被修改的(can be modified)。長度和字符序列可通過某些方法改變。

StringBuffer產生一塊內存空間,相關的追加等操作都在其中進行,所以為其添加了一句“,World”仍然是同一段內存地址上進行,sb所指向的引用沒有改變。

總之,基本數據類型,是傳值的副本;對象類型,是傳引用的副本。

實戰

下面代碼輸出結果是多少,為什麼?【美國著名軟件公司 面試題】

Java傳值和引用筆試題透析

Java傳值和引用筆試題透析

解析:

再second裡,v只是first函數里v的一個引用副本,v.i =20 通過副本改變了first中v指向對象的i的值為20。再second函數中v重新指向了新對象,再執行打印相當於打印新對象的值:

Java傳值和引用筆試題透析

因此最終結果是:

15 0

20


分享到:


相關文章: