前言
最近在學習java集合的學習過程中遇到了集合元素引用在記憶體裡存儲原理,即java中變量和引用變量在記憶體中的存儲原理,這裡簡單的整理了一下,希望能對大家對java内記憶體存儲有一個直覺的認識,如果有講的不對的地方也請大家在多多包涵并指出,廢話不多說,下面我們圍繞以下代碼來進行讨論,問輸出的四個變量的值是什麼?。
package collection;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo2 {
public static void main(String[] args) {
int a= 1;
String b = "hello";
Point p = new Point(1,2);
Collection c = new ArrayList();
c.add(p);
test(a,b,p,c);
System.out.println("a:"+a);
System.out.println("b:"+b);
System.out.println("p:"+p);
System.out.println("c:"+c);
}
public static void test(int a,String b,Point p,Collection c) {
a=2;
b=b+"world";
p.setX(3);
p = new Point(5,6);
c.clear();
c.add(p);
p.setY(7);
c = new ArrayList();
c.add(p);
}
}
類Point的代碼如下
public class Point {
private int x;
private int y;
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "Point [x=" + x + ", y=" + y + "]";
}
public boolean equals(Object obj) {
if(obj==null) {
return false;
}
if(obj==this) { //自己本身
return true;
}
if(obj instanceof Point) {
Point p = (Point)obj;
return this.x ==p.x&&this.y ==p.y;
}
return false;
}
}
首先,我們要知道jvm記憶體分為4段,棧區,堆區,代碼區,全局變量區。
堆(heap): 堆是Java對象的存儲區域,任何用new字段配置設定的Java對象執行個體和數組,都被配置設定在堆上。
棧(stack):棧又稱堆棧, 是使用者存放程式臨時建立的局部變量。這裡我們主要講這兩部分。
一開始程式從main方法進入先将下列變量a,b,p,c這些局部變量存入到棧中,所建立的對象存入到堆中(1是基本類型,存入堆中,其他引用類型直接存到堆中,該引用類型的位址放到所對應的棧中)
效果如下下圖。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL1UEVNFzYU50MrR1Tyx2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2MDN5EDOwITM4EjNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
當調用到test方法時,傳入a,b,p,c這四個局部變量,即和上面的變量都指向同一對象,有一點要注意的地方是,拼接字元串會産生新的對象,變量b會指向新對象,(虛線代表删除)p也睡指向新對象,而c.clear()把集合裡的引用删除(即黑色虛線),c.add§向集合中添加p對象()紅色曲線,c也指向新的集合。如下圖。
然後,當test方法執行完,這方法的局部變量都被清掉,然後GC開始回收對象,把不需要的對象釋放掉,畫綠線的地方都要被清除(沒有被引用的)。如下圖。
最後記憶體中的效果圖如下圖。
此時再輸出a,b,p,c的值就很好看了。
a為1
b為 “hello”
p為所指向的這個對象的toString方法 即(3,2)
c為集合中所指向的那個對象 即[(5,7)]。