close

需要上課的人員:

題目一:

請問最後印出的set.size()與xx是多少?

答案:size=2,xx=10(反白中)

題目二:

請問最後印出的字串s為何?

答案:main method(反白中)

需要上課的人員:只要其中一題沒有答對,即需要上課。

八大型別與JVM記憶體位置

在JAVA中有八種比較特殊的型別,分別是:

  • boolean

  • btye

  • short

  • char

  • int

  • float

  • long

  • double

這八個型別比較特殊的原因,在於JVM中所存在的記憶體位置。在JVM中所存在的記憶體分配如下圖:

  • String pool:所有的字串存放的地方

  • Stack pool:所有Method執行的地方

  • Heap:所有物件存放的地方

由上方的描述可以知道,所有的物件都會被放到Heap區之中,而method如果要用到物件的話,會儲存Heap的記憶體位置,Heap中再儲存物件中的所有資料,而不是Stack pool裡儲存物件的所有資料;八大型別比較奇特的部份在於,它儲存的地方不會在Heap裡,而是在Stack pool中。那這樣又會有什麼影響呢?那就是傳值(Call by value)與傳址(Call by reference);也就是說,所有的八大型別在傳遞時,因為資料不是儲在Heap區,所以在傳遞給其他method時,接受的method必須自己持有一份(傳值),而八大型別之外的,全部都是傳遞記憶體位址;換句話說,八大型別在傳遞時是傳值,而八大型別之前的是傳址

不過除了Stack pool與Heap之外,另外還有一個String pool,這個部份是String專用的,也因為有這個pool的存在,所以String這個型別在JAVA中是比較特殊的。

String型別與JVM記憶體位置

假設我們有程式碼如下:

我們來實際模擬一下JVM上的記憶體是如何處理的:

首先是Stack pool有一個main,裡面包含一個String s儲存了記憶體位址,如下圖:

再來是執行了changeWork時,並帶入參數s(傳址)。

最後是在變更s="changeWork method",所以應該是長成如下圖:

Untitled (1).png

所以最後程式執行的結果應該是:

before changeWork s=main method

in changeWork s=changeWork method

after changeWork s=changeWork method

如果你的觀念是這樣子的,那我要先恭禧你,觀念是對的,只不過結過是錯的,下圖是程式實際運行上的結果:

我們可以看到最後一行是有問題的,原因其實是因為String是一個特殊的型別,如果今天我們修改的不是String的話,那就沒有這個問題了。

我們先回頭來重新確認一下程式:

下面我們重新來繪製正確的JVM記憶體位置圖:

首先是Stack pool裡面有一個main的method,並宣告了一個String s,此時因為s有值,所以在 String pool中會有一組文字main method,而Heap則是記憶了這個String pool的記憶體位置,如下圖:

再來是執行changeWork時,一樣將利用傳址的方式傳入:

 

最後在changeWork時變更文字的記憶體位置會變成如下圖:

 

在changeWork中因為程式 s="changeWork method",所以會在String pool裡生成一個新的記憶體位置,而這個新的記憶體位置並不會被記在舊的Heap裡的 #111裡,而是被記憶在新的記憶體位置,所以結果如上圖,而程式的執行結果:

這樣我們就可以很清楚的瞭解了為什麼會如此;JVM會有如此的行為,完全是因為String是一個特殊的物件所造成的,如果今天是一個單純的物件的話,就不會這麼麻煩了。

arrow
arrow

    JAVA Programmer 發表在 痞客邦 留言(0) 人氣()