前言
最近在学习java集合的学习过程中遇到了集合元素引用在内存里存储原理,即java中变量和引用变量在内存中的存储原理,这里简单的整理了一下,希望能对大家对java内内存存储有一个直观的认识,如果有讲的不对的地方也请大家在多多包涵并指出,废话不多说,下面我们围绕以下代码来进行讨论,问输出的四个变量的值是什么?。
package collection;
import java.util.ArrayList;
import java.util.Collection;
/**
- 集合只能存放引用类型元素,并且存放的是元素的引用(地址)
- @author 杨柯
*/
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是基本类型,存入堆中,其他引用类型直接存到堆中,该引用类型的地址放到所对应的栈中)
效果如下下图。
当调用到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)]。