在构造函数中传递集合的引用是不好的设计?

时间:2012-12-12 06:39:15

标签: java

我遇到过很多类似的代码:

class AClass{
    private Iterable<String> list;
    public AClass(Iterable<String> list){ this.list = list; }
    ...
}

在此代码中,Iterable的引用直接传递给AClass。最终结果相当于将列表引用直接暴露给外部。即使你最终制作了AClass.list,它仍然允许来自AClass之外的代码来修改列表的内容,这很糟糕。

为了解决这个问题,我们将在构造函数中执行防御性复制。

但是,这种代码很常见。除了性能考虑之外,人们编写这种代码的意图是什么?

5 个答案:

答案 0 :(得分:1)

简单的回答,如果它是你自己的代码/小团队,通常只需更快,更容易,更少的内存和CPU密集型来做这样的事情。此外,有些人只是不知道更好!

答案 1 :(得分:1)

您可能需要查看copy constructor以获取熟悉的习语。

答案 2 :(得分:1)

我没有看到这种模式有什么问题。如果类表示对列表(或可迭代)进行操作的对象,那么将该列表提供给构造函数是很自然的。如果您的类无法处理对基础集合的更改,则需要对其进行修复或记录。制作该集合的副本是解决该问题的一种方法。

另一个选择是更改界面,以便只允许不可变的集合:

public AClass(ImmutableList<MyObject> objects) {
    this.objects = objects;
    ...

当然,您需要某种ImmutableList类或接口。

根据课程的用途和用户,您还可以通过记录已知的&#34;弱点&#34;:

来避免复制。
/**
 * ...
 * @param objects list of objects this AClass-object operates on.
 *                The list should not be modified during the lifetime 
 *                of this object
 */
public AClass(List<MyObject> objects) ...

答案 3 :(得分:0)

制作副本总是很好的做法,不仅因为其他人可以修改您的值,而且出于安全原因。

答案 4 :(得分:0)

如果代码在内部使用,如其他答案所指出的那样,那应该不是问题。但是,如果您作为API公开,那么有两种选择:

首先是创建一个防御性副本,然后将其返回

第二种方法是创建一个UnmodifiableCollection然后返回它,并记录试图改变集合中任何内容可能导致异常的事实。

但第一种选择更为可取。