在對象指向中,我們一定要清楚引用類型數據的堆棧二段式內存管理,下面通過一個小例子,讓我們來解析堆棧內存是如何使用的。
先附一段代碼:

class People{
 public String name;
 public int age;
 public void say(){
  System.out.println("姓名:"+name+"  年齡:"+age);
 }
}
public class Test16 {

 public static void main(String[] args) throws InterruptedException {
  People p1 =new People();
  People p2 =new People();
  p1=p2;
  p1.name="大雨";
  p1.age=21;
  p1.say();
  p2.name="狗生";
  p2.age=22;
  p2.say();
 }
}

運行結果如下圖:


這是為什么呢,其實是對象引用的問題。

先看這個例子,里面先new了兩個對象,分別問p1和p2,然后將p2的值附給了p1,這時,p1的指向就發生了變化:p1就不再指向原來的地址了,此時p1就指向了p2所指向的地址了,也就是說:p1和p2指向了同一塊堆內存。這時先給p1的屬性賦值,并且調用了p1的say方法,這個時候控制臺就打印出來p1所指向的堆地址(實際此時p2指向的也是這個堆地址);然后又給p2的屬性賦值,并且調用了p2的say方法,這個時候控制臺就會打印出來p2所指向的堆地址(實際此時p1指向的也是這個堆地址),兩次打印出來的字符串是不一樣的,因為數值發生了改變。

下面附堆棧內存圖來進一步解釋。

第一次調用say方法時內存狀態:


第二次調用say方法時的內存狀態:



上面第二個圖畫錯了,應該是在第一個name和age改成“狗生”和“22”,第二個name和age還是空的。


將上面的代碼稍微改動一下:
class People{
 public String name;
 public int age;
 public void say(){
  System.out.println("姓名:"+name+"  年齡:"+age);
 }
}
public class P1withP2 {
 public static void main(String[] args) throws InterruptedException {
  People p1 =new People();
  People p2 =new People();
  p1=p2;
  p1.name="大雨";
  p1.age=21;
  p2.name="狗生";
  p2.age=22;
  p1.say();
  p2.say();
 }
}

我們再看看運行結果:


再看這個例子,里面先new了兩個對象,分別問p1和p2,然后將p2的值附給了p1,這時,p1的指向就發生了變化:p1就不再指向原來的地址了,此時p1就指向了p2所指向的地址了,也就是說:p1和p2指向了同一塊堆內存。這時先給p1的屬性賦值(實際此時p2指向的也是這個堆地址);然后又給p2的屬性賦值(實際此時p1指向的也是這個堆地址),這個時候就出現了堆內存里數據的覆蓋,這個時候調用了p1的say方法和p2的say方法,實際上兩次打印出來的字符串是一樣的,都是修改后的數據,因為兩個引用都是指向同一塊內存地址。

下面附堆棧內存圖來進一步解釋。

第一次和第二次調用say方法時內存狀態:



上面第三個圖畫錯了,應該是在第一個name和age改成“狗生”和“22”,第二個name和age還是空的。


這就是對象引用的時候內存管理的變化,希望這個例子能夠對大家更好理解內存管理起到一定幫助作用。