-1

谁能告诉我在JAVA中类的构造函数的引用参数方面什么是防御性复制

非常感谢

4

1 回答 1

1

鉴于我可以从问题中提取的内容,我想问题可以总结如下......

让我们从这个开始:

class NotSafeAtAll
{
    private final List<X> list;

    public NotSafeAtAll(final List<X> list)
    {
        this.list = list;
    }
}

这个类有一个大问题:它将列表引用复制为其成员字段。这意味着如果构造函数的调用者修改了这个列表,变化也会反映在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);
}

调用者修改返回列表的任何尝试都将失败。

那么,故事结束了吗?

不。

X只有所有实例都是不可变的,它才能结束。不幸的是,非常经典且过度使用的 bean 模式无法保证这一点。但这是另一个故事。

于 2013-06-02T03:48:18.933 回答