在对象指向中,我们一定要清楚引用类型数据的堆栈二段式内存管理,下面通过一个小例子,让我们来解析堆栈内存是如何使用的。
先附一段代码:
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还是空的。
这就是对象引用的时候内存管理的变化,希望这个例子能够对大家更好理解内存管理起到一定帮助作用。