阿里面試官:兄弟,說說Java到底是值傳遞還是引用傳遞

01、值傳遞 VS 引用傳遞

首先,我們必須要搞清楚,到底什麼是值傳遞,什麼是引用傳遞,否則,討論 Java 到底是值傳遞還是引用傳遞就顯得毫無意義。

當一個參數按照值的方式在兩個方法之間傳遞時,調用者和被調用者其實是用的兩個不同的變量——被調用者中的變量(原始值)是調用者中變量的一份拷貝,對它們當中的任何一個變量修改都不會影響到另外一個變量。

而當一個參數按照引用傳遞的方式在兩個方法之間傳遞時,調用者和被調用者其實用的是同一個變量,當該變量被修改時,雙方都是可見的。

Java 程序員之所以容易搞混值傳遞和引用傳遞,主要是因為 Java 有兩種數據類型,一種是基本類型,比如說 int,另外一種是引用類型,比如說 String。

基本類型的變量存儲的都是實際的值,而引用類型的變量存儲的是對象的引用——指向了對象在內存中的地址。值和引用存儲在 stack(棧)中,而對象存儲在 heap(堆)中。


阿里面試官:兄弟,說說Java到底是值傳遞還是引用傳遞


之所以有這個區別,是因為:

  • 棧的優勢是,存取速度比堆要快,僅次於直接位於 CPU 中的寄存器。但缺點是,棧中的數據大小與生存週期必須是確定的。
  • 堆的優勢是可以動態地分配內存大小,生存週期也不必事先告訴編譯器,Java 的垃圾回收器會自動收走那些不再使用的數據。但由於要在運行時動態分配內存,存取速度較慢。

02、基本類型的參數傳遞

眾所周知,Java 有 8 種基本數據類型,分別是 int、long、byte、short、float、double 、char 和 boolean。它們的值直接存儲在棧中,每當作為參數傳遞時,都會將原始值(實參)複製一份新的出來,給形參用。形參將會在被調用方法結束時從棧中清除。

來看下面這段代碼:

<code>

public

class

PrimitiveTypeDemo

{

public

static

void

main

(

String[] args

)

{

int

age =

18

; modify(age); System.

out

.println(age); }

private

static

void

modify

(

int

age1

)

{ age1 =

30

; } }/<code>

1)main 方法中的 age 是基本類型,所以它的值 18 直接存儲在棧中。

2)調用 modify() 方法的時候,將為實參 age 創建一個副本(形參 age1),它的值也為 18,不過是在棧中的其他位置。

3)對形參 age 的任何修改都只會影響它自身而不會影響實參。


阿里面試官:兄弟,說說Java到底是值傳遞還是引用傳遞


03、引用類型的參數傳遞

來看一段創建引用類型變量的代碼:

<code>Writer writer = 

new

Writer(

18

,

"沉默王二"

);/<code>

writer 是對象嗎?還是對象的引用?為了搞清楚這個問題,我們可以把上面的代碼拆分為兩行代碼:

<code>

Writer

writer;

writer

= new Writer(

18

,

"沉默王二"

);/<code>

假如 writer 是對象的話,就不需要通過 new 關鍵字創建對象了,對吧?那也就是說,writer 並不是對象,在“=”操作符執行之前,它僅僅是一個變量。那誰是對象呢?new Writer(18, "沉默王二"),它是對象,存儲於堆中;然後,“=”操作符將對象的引用賦值給了 writer 變量,於是 writer 此時應該叫對象引用,它存儲在棧中,保存了對象在堆中的地址。

每當引用類型作為參數傳遞時,都會創建一個對象引用(實參)的副本(形參),該形參保存的地址和實參一樣。

來看下面這段代碼:

<code>

public

class

ReferenceTypeDemo

{

public

static

void

main

(

String[] args

)

{ Writer a =

new

Writer(

18

); Writer b =

new

Writer(

18

); modify(a, b); System.

out

.println(a.getAge()); System.

out

.println(b.getAge()); }

private

static

void

modify

(

Writer a1, Writer b1

)

{ a1.setAge(

30

); b1 =

new

Writer(

18

); b1.setAge(

30

); } }/<code>

1)在調用 modify() 方法之前,實參 a 和 b 指向的對象是不一樣的,儘管 age 都為 18。


阿里面試官:兄弟,說說Java到底是值傳遞還是引用傳遞


2)在調用 modify() 方法時,實參 a 和 b 都在棧中創建了一個新的副本,分別是 a1 和 b1,但指向的對象是一致的(a 和 a1 指向對象 a,b 和 b1 指向對象 b)。


阿里面試官:兄弟,說說Java到底是值傳遞還是引用傳遞


3)在 modify() 方法中,修改了形參 a1 的 age 為 30,意味著對象 a 的 age 從 18 變成了 30,而實參 a 指向的也是對象 a,所以 a 的 age 也變成了 30;形參 b1 指向了一個新的對象,隨後 b1 的 age 被修改為 30。


阿里面試官:兄弟,說說Java到底是值傳遞還是引用傳遞


修改 a1 的 age,意味著同時修改了 a 的 age,因為它們指向的對象是一個;修改 b1 的 age,對 b 卻沒有影響,因為它們指向的對象是兩個。

程序輸出的結果如下所示:

<code>

30

18

/<code>

果然和我們的分析是吻合的。

04、最後

好了,我親愛的讀者朋友,以上就是本文的全部內容了。看完之後,再遇到面試官問 Java 到底是值傳遞還是引用傳遞時,就不用擔心被刁難了。我是沉默王二,一枚有趣的程序員。原創不易,莫要白票,請你為本文點贊個吧,這將是我寫作更多優質文章的最強動力。


作者:沉默王二
鏈接:
https://juejin.im/post/5ea10ca4518825736d27ae23


分享到:


相關文章: