任何人都可以告诉我在JAVA中类的构造函数的引用参数方面的防御性复制是什么
非常感谢
答案 0 :(得分:1)
鉴于我可以从问题中提取,我猜这个问题可归纳如下......
让我们从这开始:
class NotSafeAtAll
{
private final List<X> list;
public NotSafeAtAll(final List<X> list)
{
this.list = list;
}
}
这个类有一个很大的问题:它将列表 reference 复制为其成员字段。这意味着如果构造函数的调用者修改了此列表,则更改也将反映在NotSafeAtAll
实例中。
这就是“防御性复制”发挥作用的地方。考虑:
class ALittleMoreSafe
{
private final List<X> list;
public ALittleMoreSafe(final List<X> list)
{
this.list = new ArrayList<X>(list);
}
}
现在,该类有自己的列表副本;如果调用者修改了它作为参数传递给构造函数的列表,则ALittleMoreSafe
实例不会受到影响。
但当然,故事并没有在这里结束。现在考虑后一个类中有一个方法返回它收到的列表作为参数:
class ALittleMoreSafe
{
private final List<X> list;
public ALittleMoreSafe(final List<X> list)
{
list = new ArrayList<X>(list);
}
public List<X> unsafeGetList()
{
return list;
}
}
你输了!即使您的构造函数是安全的,事实是您将引用返回到内部列表;并且调用者可以通过此引用修改列表。
再次,防御性副本可以拯救你,但有一个更好的解决方案:确保你返回的列表是不可变的:
public List<X> safeGetList()
{
return Collections.unmodifiableList(list);
}
调用者修改返回列表的任何尝试都将失败。
那么,故事结束了吗?
NO。
只有当所有X
实例都是不可变的时,它才能结束。不幸的是,非常经典,过度使用的bean模式除了保证之外。但这是另一个故事。