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
。是我的错。因此,我对我的答案做了一些改进。