Java 如何使可变对象列表不可变

Java 如何使可变对象列表不可变,java,collections,immutability,Java,Collections,Immutability,大家好,我在采访中被问到这样一个问题:在一个不可变的类中有对象列表,这个类真的是不可变的吗,可以修改什么,以及如何防止它。我给出了下面的解决方案 public final class A{ final List<B> listOfB; // B is mutable public List<B> getListOfB(){ return Collections.unmodifiableList(this.listOfB); } } 公开期

大家好,我在采访中被问到这样一个问题:在一个不可变的类中有对象列表,这个类真的是不可变的吗,可以修改什么,以及如何防止它。我给出了下面的解决方案

public final class A{
   final List<B> listOfB; // B is mutable

   public List<B> getListOfB(){
      return Collections.unmodifiableList(this.listOfB);
   }
}
公开期末甲级{
最终列表listOfB;//B是可变的
公共列表getListOfB(){
返回集合.unmodifiableList(this.listOfB);
}
}
现在他说,即使在获得getListOfB()之后,他也可以更改“B”实例,并希望我也避免这样做。然后我说

public List<B> getListOfB(){
   List<B> ret;
   for(B b: this.listOfB){
       ret.add(b.clone()); // basically make a deep copy of 'b' for return list
   }
   return ret;
} 
公共列表getListOfB(){
列表ret;
对于(B:这个列表B){
ret.add(b.clone());//基本上为返回列表制作一个“b”的深度副本
}
返回ret;
} 
面试官没有回应任何说对或错的事情

这个解决方案肯定有效。但是有没有更好的方法,我的方法非常笨拙,需要太多额外的内存


PS:假设B不能是不可变的。

假设
B
是接口或接口
A
的实现,您可以分别使用
B
A
java.net.Proxy
包装
listOfB
的每个元素,它通过抛出一个
UnsupportedOperationException
来拦截所有修改调用


更详细地说,用实现
a
java.net.Proxy
包装实例替换
listOfB
的每一项。然后,每当有人获取
listOfB
的一项时,他将获得包装的实例。每当有人对这样一个包装的项目调用setter时,拦截该调用并抛出一个
UnsupportedOperationException
。希望你能理解我的意思。它基本上就是集合。不可修改的xxx()所做的。如果您了解所有可能修改
listOfB
项状态的方法,
B
不一定是
POJO
。只要确保您的包装器通过抛出异常来替换所有修改方法。

如果
B
无法设置为不可变,那么返回克隆列表是您唯一的选择——前提是您可以克隆它们在您的示例中,类a不是不可变的,因为您不能保证您确实拥有
listOfB
中的对象,所以如果您克隆
getListOfB()
中的元素,这并不重要。您需要在类A的构造函数中克隆
listOfB
的元素。为什么假设它为POJO?类还可以包含公共数据成员。我认为如果不包装泛型类型,则它与此无关。只要你知道关于
B
的一切,它就不一定是一个
POJO
。是我的错。因此,我对我的答案做了一些改进。