关于java中集合类的不可变包装的一些思考

众所周知,java中的各种集合类,比如List,Set,Map等都是mutable的类,为了安全性,经常会利用到Collection类中的不可变包装的方法将其包装成不可变类型的变量,比如Collections.unmodifiableList()方法。
但是倘若进行如下代码,会发现尽管使用了该方法进行包装但是内部数据还是可以发生变化,于时,针对这个问题我展开了思考。

		List<Date> dateList = new ArrayList<>();
        Date date = new Date();
        dateList.add(date);
        System.out.println(dateList.get(0));
        List<Date> unmodList = Collections.unmodifiableList(dateList);
        unmodList.get(0).setTime(100);
        System.out.println(unmodList.get(0));
        System.out.println(dateList.get(0));

输出:
在这里插入图片描述
于时我发现尽管如此,unmodList中存放的Date对象也可以被改变。
于是我再次看了一下immutable类型的定义:
在这里插入图片描述
之后查看不可变包装的源码发现该函数返回一个UnmodifiableList类型变量
在这里插入图片描述
之后查看该类型的源码
在这里插入图片描述
然后发现UnmodifiableList类利用了装饰器模式将List类进行包装,其中变量list为final的引用,然后重写了List中的所有方法。
在这里插入图片描述
然后将List类中所有mutator方法都重写,抛出异常,其他非mutator方法则直接委派给list去做,依此来实现不可变包装。

在代码中继续进行实验。

        List<Date> dateList = new ArrayList<>();
        Date date = new Date();
        dateList.add(date);
        System.out.println(dateList.get(0));
        List<Date> unmodList = Collections.unmodifiableList(dateList);
        unmodList.get(0).setTime(100);
        System.out.println(unmodList.get(0));
        System.out.println(dateList.get(0));
        System.out.println(unmodList==dateList);
        System.out.println(unmodList.get(0)==dateList.get(0));
        Date date1 = new Date();
        dateList.set(0,date1);
        System.out.println(unmodList.get(0));

输出为:
在这里插入图片描述
由此可以看出unmodList和dateList指向的不是一个内存空间,但是unmodList中的list指向的是dateList,也就是说dateList.get(i)与unmodList.get(i)指向的对象永远是同一个。
这样在dateList中进行修改的话也会导致看似不可变的unmodList发生变化。
所以要避免未包装过的引用泄露出去。

最后根据实验结果画出原来代码中

		List<Date> dateList = new ArrayList<>();
        Date date = new Date();
        dateList.add(date);
        System.out.println(dateList.get(0));
        List<Date> unmodList = Collections.unmodifiableList(dateList);
        unmodList.get(0).setTime(100);

相应的snapshot图如下:
在这里插入图片描述
由于那个包装类中只有一个final修饰的list引用指向被包装的类,所以应该是这样的
但是由于我不太清楚snapshot是否要考虑内部实现,所以也有可能是下面这样的画法:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值