根据构造函数的引用参数进行防御性复制

时间:2013-06-02 02:06:50

标签: java defensive-copy

任何人都可以告诉我在JAVA中类的构造函数的引用参数方面的防御性复制是什么

非常感谢

1 个答案:

答案 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模式除了保证之外。但这是另一个故事。