关于不可变类防御性复制
我有一个关于创建Immutable类的查询。 以下是我考虑的要点:
- 让课程最终
- 使所有成员最终,在静态块或构造函数中显式设置它们
- 让所有成员都私密
- 否修改状态的方法
- 要非常小心地限制对可变成员组件的访问(请记住该字段可能是最终的,但对象仍然可以是可变的。即私有最终日期imStillMutable) – 请参阅防御性复制或其表兄弟拷贝构造函数以获取更多信息。
但是我完全不明白这一点,请你告诉或给我一个例子,其中5点在这个例子中是清楚的?
第5点建议,任何时候你有任何方法可以返回与可变对象有关的东西,你想要创建一个独立于私有状态的副本。 例如:
public final class Foo { private final List strings; public Foo(List strings) { // Defensive copy on construction. Protects from constructing // code mutating the list. this.strings = new ArrayList (strings); } public List getStrings() { // Defensive copy on read. Protects from clients mutating the list. return new ArrayList (strings); } }
请注意,只有在状态可变时才需要防御性复制。 例如,如果您使用ImmutableList
(例如来自Guava)作为上述类中的状态,则需要在构造时创建新列表(除非输入也是ImmutableList
),而不是在getStrings
。
另请注意,在这种情况下, String
是不可变的,因此我们不需要复制每个字符串。 如果这是List
我们需要创建一个新列表和每个元素的新副本作为防御副本的一部分。 正如你所看到的,当你所有的状态也是不可变的时候,生活变得更加简单。
final
意味着指针不能指向另一个引用。 例如:
final Object obj = new Object(); obj = new Object(); //Invalid
但是final
不会阻止修改对象:
obj.setWhatever("aaa"); //Perfectly valid
如果您没有限制对成员的访问权限,那么任何人都可以获取该对象并对其进行修改。
例如: yourClass.getObject().setWhatever("aaa").
防御性复制意味着getObject()
不会直接返回该对象,但它会复制它然后返回它。 这样,如果调用者修改返回的对象,它将不会修改该类的原始成员。