本篇為記錄不同的Java資料型態在記憶體中的變化情形,參考JVM 的 Stack 和 Heap並重點摘要。
Java語言中,資料型別分為基本型別
及參考(類別)型別
2種,特性如下:
byte
、short
、int
、long
、float
、double
、boolean
、char
特性
:
不屬於基本型別的,都屬於此類別,這種類型通常都需要用 new
去創建,如 User user = new User("Mark")
; 。特性
:
儲存函數路徑
及區域變數
。變數a
的123
。函數路徑
:Stack 內的變數值為物件實體在 Heap 中回傳所在的記憶體位址,如上圖的0x1234。後進先出
(FILO) 的容器,具有存取速度快
和管理簡單的特點。下往上堆
,如圖b在a上面。區域變數只能存在methods中
),所以由系統自行去產生和回收空間即可,不用特別設計垃圾回收機制。物件實體
的屬性資料
,如圖中的name :Mark
,並產生位址:0x1234
。記憶體位址
給stack
。沒有立即給值
的情況下,也是要等new一個該類別的物件實體,才會在heap中建立該物件的值,並把預設值存放進去
,之後再把記憶體位址
給stack
。共享資料
,所以同 Process
底下的其他 Thread 也可以進行存取。Garbage Collection
機制,因為無法掌握物件實體的生命週期,所以存取速度慢
,但是GC是否有提升效能的部分還是有待討論。兩個物件實體:當a物件 = b物件,代表b物件在stack中只是把heap的位址
給a物件。
兩個區域變數:a = b,代表區域變數b在stack中把區域變數a的值給覆蓋
。
運作如下圖
當在heap中沒被參考到的物件,也就是沒有變數儲存他的位址
(如上圖0x12),就由JVM的GC機制
回收並釋放記憶體空間。
參數
使用基本型別跟類別型別的差異: static void passValue(double value) {
value = 20.0;
}
static void passReference(Pen reference) {
reference.price = 20.0;
}
public static void main(String[] args) {
double price = 10.0;
passValue(price);
System.out.println(price); // 10
Pen myPen = new Pen();
myPen.price = 10.0;
passReference(myPen);
System.out.println(myPen.price); // 20
}
解:
當資料為基本型別時:
price
值為10.0
的空間。passValue
調用該值成為該方法的參數
時,會在stack再建立一個空間儲存該參數(value
)的值10.0
。value
被賦予新的值20.0
。passValue
運作結束,區域變數value
的生命週期也結束了。price
還是一樣沒有變化為10.0
。當資料為類別型別時:
price
值為10.0
的空間,並回傳位址0x12
給stack並儲存在變數myPen
。passReference
調用該值(位址0x12
)成為該方法的參數
時,會在stack再建立一個空間儲存該參數(reference
)的值0x12
。reference
的屬性price
值在heap
中會被更改為20.0
。passReference
運作結束,區域變數reference
的生命週期也結束了。myPen
因為屬性price
的值在heap
中已經被更改為20.0
,所以最後print出來的值就變為20.0。參考資料:
JVM 的 Stack 和 Heap:https://blog.marklee.tw/java-interview-jvm-stack-heap/