使用不可变对象,将包含的集合包装为不可修改的位置是正确的?我看到3个选项:
在不可变对象的工厂中:
public class ImmutableFactory {
public Immutable build(){
List<Integer> values = new ArrayList<Integer>();
values.add(1);
values.add(2);
values.add(3);
return new Immutable(Collections.unmodifiableList(values), "hello");
}
}
在immutable的构造函数
中public class Immutable {
private final List<Integer> values;
private final String hello;
public Immutable(List<Integer> values, String hello) {
this.values = Collections.unmodifiableList(values);
this.hello = hello;
}
public List<Integer> getValues() {
return values;
}
public String getHello() {
return hello;
}
}
在immutable的访问者中(如果适用)。
public class Immutable {
private final List<Integer> values;
private final String hello;
public Immutable(List<Integer> values, String hello) {
this.values = values;
this.hello = hello;
}
public List<Integer> getValues() {
return Collections.unmodifiableList(values);
}
public String getHello() {
return hello;
}
}
还有其他选择吗?哪一种适当?
答案 0 :(得分:4)
我会说如果你创建了Immutable集合,那么你需要保护自己免受某人修改作为构造函数参数的列表的影响,你应该保护性地复制它。
public Immutable(List<Integer> values, String hello) {
this.values = Collections.unmodifiableList(new ArrayList<Integer>(values));
this.hello = hello;
}
我个人很久以前就切换到了Guava个集合,因为你可以找到不可变集合的接口。你的构造函数看起来像那样:
public Immutable(ImmutableList<Integer> values, String hello) {
this.values = values;
this.hello = hello;
}
你确定你收到的论点不会被任何人修改。
在不可变类中保留对不可变列表的引用通常是个好主意,因为它可以保证你不会错误地修改它。
我认为Case(1)只有当工厂方法是创建不可变集合的唯一方法时才有意义,即使这样,当有人重构这些类时它也可能会中断。除非有其他限制,否则最好创建自给自足的类。
答案 1 :(得分:1)
首先,您所有地方的代码确实是不可变的但只是因为Integer
是不可变的。
如果您改为使用private final List<SomeCustomClass> values;
,则Collections.unmodifiableList(values);
无法保证列表中的个别SomeCustomClass
是不可变的。 你必须为此编码。
话虽如此,另一种选择是对列表进行 defencive deep copy 。这种方法也提供了不变性。