我有一个关于创建Immutable类的查询。以下是我考虑的要点:
但是我根本不完全理解这一点,你能告诉或给我一个例子,其中5点在这个例子中是清楚的吗?
答案 0 :(得分:5)
第5点建议,只要你有任何方法返回与可变对象有关的东西,你就要创建一个独立于私有状态的副本。例如:
public final class Foo
{
private final List<String> strings;
public Foo(List<String> strings)
{
// Defensive copy on construction. Protects from constructing
// code mutating the list.
this.strings = new ArrayList<String>(strings);
}
public List<String> getStrings()
{
// Defensive copy on read. Protects from clients mutating the list.
return new ArrayList<String>(strings);
}
}
请注意,只有在状态可变时才需要防御性复制。例如,如果您使用ImmutableList
(例如来自Guava)作为上述类中的状态,则需要在构造时创建新列表(除非输入也是ImmutableList
)但是getStrings
中不。
另请注意,在这种情况下String
是不可变的,因此我们不需要复制每个字符串。如果这是List<StringBuilder>
,我们需要创建一个新列表和每个元素的新副本作为防御副本的一部分。正如你所看到的,当你所有的状态也是不可变的时候,生活会变得更简单。
答案 1 :(得分:3)
final
表示指针不能指向另一个引用。
例如:
final Object obj = new Object();
obj = new Object(); //Invalid
但final
并不妨碍修改对象:
obj.setWhatever("aaa"); //Perfectly valid
如果您没有限制对成员的访问权限,那么任何人都可以获取该对象并进行修改。
例如:yourClass.getObject().setWhatever("aaa").
防御性复制意味着getObject()
不会直接返回该对象,但它会复制该对象然后将其返回。这样,如果调用者修改返回的对象,它将不会修改类的原始成员。