在路上

 找回密码
 立即注册
在路上 站点首页 学习 查看内容

深入Java深浅拷贝、immutable、unmodifiable

2017-2-7 13:42| 发布者: zhangjf| 查看: 453| 评论: 0

摘要: 建议:函数调用的时候,调用方传给被调用方的参数,如果在调用之后还会被修改,那么调用方应该给被调用方传一个当时的拷贝,深拷贝,否则: 可能被调用方是异步执行的,如果调用函数之后,参数发生了修改,那么被调 ...
建议:函数调用的时候,调用方传给被调用方的参数,如果在调用之后还会被修改,那么调用方应该给被调用方传一个当时的拷贝,深拷贝,否则: 可能被调用方是异步执行的,如果调用函数之后,参数发生了修改,那么被调用方执行的时候,看到的就是被修改之后的数据,这将导致严重、隐蔽、非必现的BUG,而这种BUG是最让人头疼的 可能被调用方会修改传入的参数,这就导致函数执行完毕之后,调用方看到的数据发生了非预期的变化,这同样会导致严重、隐蔽的BUG 深拷贝:这里需要弄清楚深浅拷贝的区别,用“=”号给非基本类型赋值,均是浅拷贝,例如List,以下代码就是浅拷贝:
  1. List<Integer> list1 = new ArrayList<>();
  2. list1.add(1);
  3. List<Integer> list2 = list1;
  4. list1.add(2);
复制代码

代码执行完毕之后,list2将包含整数1和2。
而以下代码则是深拷贝:

  1. List<Integer> list1 = new ArrayList<>();
  2. list1.add(1); List<Integer> list2 = new ArrayList<>(list1);
  3. list1.add(2);
复制代码

代码执行完毕之后,list2将只包含整数1,不包含整数2。

Immutable对象:上述情形如果遇到immutable对象,即不可变对象,其实是不需要深拷贝的(不仅不需要,还应该杜绝拷贝,因为纯属浪费)。但是前提是对象是真正的immutable。反面例子为:
  1. public class NonStrictlyImmutable {
  2. private final List<Integer> mList = new ArrayList<>();
  3. public List<Integer> getList() {
  4. return mList;
  5. }
  6. }
复制代码
mList成员设置为了private final,NonStrictlyImmutable对象实例化完成后mList所引用的实际对象也不可再被改变,然而mList这个List的元素确是可以改变的,nonStrictlyImmutable.getList().add(1)并不会报编译错误,而这一行代码却实实在在改变了nonStrictlyImmutable对象的值!
而如果getList()函数不直接返回mList引用,创建一个副本,或者使其不可被改变,则可以达到”严格意义上的“immutable。例如:
  1. public class NonStrictlyImmutable {
  2. private final List<Integer> mList = new ArrayList<>();
  3. public List<Integer> getList() {
  4. // 以下两种方式都可以,各有优劣
  5. // return new ArrayList<>(mList);
  6. // return Collections.unmodifiableList(mList);
  7. return Collections.unmodifiableList(mList);
  8. }
  9. }
复制代码

上面两种方式各有优劣:前者允许对新获取到的副本进行修改操作而不会抛出异常,但会把底层数组数据创建多份;后者不会创建多份底层数组数据,但是如果对getList()返回的引用进行修改操作,将会抛出异常;见仁见智。

unmodifiable:unmodifiable不等于immutable,所以对于前面提到的建议做法,直接传入unmodifiable是不对的,因为这样只能阻止被调用方修改传入数据后导致调用方出错,并不能阻止调用方修改后导致被调用方出错。unmodifiable并未拷贝底层数组数据,而是实现了另外一个List的实现类,该类的修改操作均抛出异常。 https://github.com/Piasy/notes/blob/master/misc/copy.md

最新评论

小黑屋|在路上 ( 蜀ICP备15035742号-1 

;

GMT+8, 2025-7-9 13:27

Copyright 2015-2025 djqfx

返回顶部