栈内存和堆内存(List集合为什么会被覆盖)

本文详细解析了栈内存与堆内存的区别,并探讨了List集合覆盖现象的原因。通过实例说明了对象引用与实际对象的区别,以及为何在循环中bList被覆盖而aModel未受影响。解决方法在于理解对象生命周期和内存管理,避免在外层创建并共享引用。
摘要由CSDN通过智能技术生成

栈内存和堆内存(List集合为什么会被覆盖)

区别

  • 栈内存:基本数据类型及对象的引用(指的是所new出的对象在堆中的地址)会存放在栈中。
  • 堆内存:凡是new出的对象都会存放在堆中,数组也是一样的。堆里存放的都是实体,实体可以封装数据,一个或多个(属性),堆内的数据不会随意被释放,Java有垃圾回收机制(GC),当堆内的数据不被使用时会被标记为垃圾,垃圾回收机制会对数据进行不定时的收取释放。

问题描述

如图一A和B两个实体,利用这两个实体,使最终输出的结果为图二

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yiOvcIFx-1649666200442)(C:\Users\TAIJI\AppData\Roaming\Typora\typora-user-images\image-20220411110803993.png)]

图一

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CU6SOjsE-1649666200444)(C:\Users\TAIJI\AppData\Roaming\Typora\typora-user-images\image-20220411125931250.png)]

图二

List集合覆盖问题重现

假如i=3,j=3,判断一下以下代码输出的结果是什么呢

@Test
public void test() throws Exception {
    A aModel = null;
    List<A> aList = Lists.newArrayList();
    B bModel = null;
    List<B> bList = Lists.newArrayList();
    for(int i=0; i<3; i++) {
        aModel = new A();
        bList.clear();
        for(int j=0; j<3; j++) {
            bModel = new B();
            bModel.setId(i+" "+j);
            bList.add(bModel);
        }
        aModel.setId(i+"");
        aModel.setbList(bList);
        aList.add(aModel);
    }
    for(A a : aList) {
        System.out.println(a.getId());
        a.getbList().forEach(t -> System.out.println(t.getId()));
    }
}

运行下发现结果是

0
2 0
2 1
2 2
1
2 0
2 1
2 2
2
2 0
2 1
2 2

从结果看来,这并不是我们想要的结果,观察结果发现每个A中的id是不一样的,而bList是一样的,所有的bList的值是最后一次放进去的值,那之前的值呢,被覆盖了?是这样的,bList在重复清空再利用的过程中被覆盖了,那为什么aModel,bModel没有被覆盖呢?

List 集合覆盖问题解释

在第一点已经讲了栈内存和堆内存里面所存的数据以及区别,现在利用栈内存和堆内存解释一下
对象没new之前是不存在的,new之后其new的内容存在堆中,它的引用存在栈中,栈中的引用存储的是new出对象的首地址,如上述代码aModel,bModel是在最外层定义的,但并未new,循环中每new出一个对象就会在堆中多一个对象,而aModel,bModel中的地址也会指向最新new出的对象(aModel,bModel的旧地址已经通过集合的add方法放入集合,输出时还可以被找到),bList是集合,在栈中存储的是首地址,bList被new出来之后在堆中顺序排列。

所以发现上面代码的问题了吗,bList不应该在最外层被new出来,如若在最外层被new出,那栈中存储的地址就固定了,堆中对应的实体位置也就固定了,改变bList,那所有aModel实体中的bList都会被改变。

正确代码

解决方法就是,bList在最外层赋值为空,在第一层循环内new出List集合,这样每次存入aModel中的bList的地址就不一样了,指向堆中的实体就不是同一个了。

@Test
public void test() throws Exception {
    A aModel = null;
    List<A> aList = Lists.newArrayList();
    B bModel = null;
    List<B> bList = null;
    for(int i=0; i<3; i++) {
        aModel = new A();
        bList = Lists.newArrayList();
        for(int j=0; j<3; j++) {
            bModel = new B();
            bModel.setId(i+" "+j);
            bList.add(bModel);
        }
        aModel.setId(i+"");
        aModel.setbList(bList);
        aList.add(aModel);
    }
    for(A a : aList) {
        System.out.println(a.getId());
        a.getbList().forEach(t -> System.out.println(t.getId()));
    }
}

结果为

0
0 0
0 1
0 2
1
1 0
1 1
1 2
2
2 0
2 1
2 2
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值