我們常說的Java內存主要分為四大塊(寄存器不在考慮之內,我們無法用代碼來操控它):stack(棧)、heap(堆)、data segment(數據區)、code segment(代碼區)。它們的主要用途如下圖所示:
而在上面四個當中,我們經常談論的是右邊那兩個家伙——stack和heap。今天我們就來聊聊Java代碼在運行的過程中,在stack和heap中到底是什么樣子的吧。
我們先看下面一段代碼:
public static void main(String[] args) { TestReference testReference = new TestReference(); int age = 1; Person xiaoqiang = new Person("小強", 21); Person xiaoming = new Person("小明", 22); testReference.selfPlus(age); System.out.println("age經過selfPlus方法的處理后為:" + age); testReference.changeName(xiaoqiang); System.out.println("小強經過changeName方法的處理后的名字為:" + xiaoqiang.getName()); testReference.changeAge(xiaoming); System.out.println("小明經過changeAge方法的處理后的年齡為:" + xiaoming.getAge()); } public void selfPlus(int i) { i = i + 1; } public void changeName(Person person) { person = new Person("小剛"); } public void changeAge(Person person) { person.setAge(25); }
執行完以上代碼,會打印出什么內容呢?如果你Java基礎還可以,那么很容易就能知道會輸出什么內容,想要知道以上代碼會打印什么內容,需要你明白Java代碼在stack和heap中是怎么工作的。下面我們結合幾張圖來看看:
int i = 1; Person xiaoqiang = new Person("小強", 21); Person xiaoming = new Person("小明", 22);
當我們執行完上面三行代碼時,內存中的情況如下圖所示:
我們知道stack是用來存放變量的,所以age、xiaoqiang和xiaoming三個變量會被存放到stack里,而age又是int類型,所以它的值也會被存放在stack里面。xiaoqiang和xiaoming為Person類型的引用變量,所以stack只會存放它們的一個引用,也就是對應對象的內存地址,而它們真正的內容被存放在了heap里面。
當執行到testReference.selfPlus(i);時,selfPlus(int i)方法被調用,此時會在stack中為形參I開辟一塊內存空間,並將其值設置為1,此時內存中的情況如下:
因為調用selfPlus(int i)方法時,將age作為形參傳遞給該方法,相當於將age的值復制一份給i,所以現在i的值為1,接着執行i = i + 1;此時i的值被修改為2,如圖:
此時被修改的只是age的副本,而並非age本身,所以age仍為1,當selfPlus(int i)方法被執行完,i被銷毀,age不變。接下來看xiaoqiang,當調用changeName(Person person)方法時,會在stack中為person分配一塊空間,里面存放的是xiaoqiang指向的地址,如圖:
然后執行到person = new Person("小剛");時,由於又new了一個Person對象,所以在堆中會新建一個person,姓名叫小剛,並且會將person執行小剛的地址,如圖:
此時,person指向的對象由小強變成了小剛,但是xiaoqiang所指向的對象仍然是小強,並沒有發生任何變化。當changeName方法執行完以后,person被銷毀,而小剛也會因為沒有任何對象對其進行引用,隨后被垃圾回收器回收掉。
下面到了最后一個方法了,當執行testReference.changeAge(xiaoming);時,調用changeAge(Person person)方法,同樣會在stack中為person分配一塊空間,這次里面存放的是xiaoming對應的內存地址,如圖:
然后執行person.setAge(25);,此時person指向的對象為小明,所以在執行setAge方法時,修改的就是heap中小明的屬性值,此時小明的年齡被修改為25,。方法執行完畢,person被銷毀,內存中最終結果如下:
內存中的最終情況就如上圖所示,當然當main方法執行完以后,之前創建的所有對象都會被銷毀。OK,每天上班做項目的你是不是把一些基礎的東西忘了呢?如果是的話就趕快來補一補吧,好處還是很多的。