3 回答

TA贡献1785条经验 获得超8个赞
以下是不可变对象的严格要求。
最终上课
使所有成员成为最终成员,在静态块或构造函数中显式设置它们
将所有成员设为私人
否修改状态的方法
要特别注意限制对可变成员的访问(请记住,该字段可能final是可变的,但对象仍然可以是可变的。即private final Date imStillMutable)。defensive copies在这种情况下,您应该这样做。
上课的final原因很微妙,常常被忽略。如果不是最终的人,他们可以自由地扩展您的类,覆盖public或protected行为,添加可变属性,然后提供其子类作为替代。通过声明该类,final您可以确保不会发生这种情况。
要查看实际问题,请考虑以下示例:
public class MyApp{
/**
* @param args
*/
public static void main(String[] args){
System.out.println("Hello World!");
OhNoMutable mutable = new OhNoMutable(1, 2);
ImSoImmutable immutable = mutable;
/*
* Ahhhh Prints out 3 just like I always wanted
* and I can rely on this super immutable class
* never changing. So its thread safe and perfect
*/
System.out.println(immutable.add());
/* Some sneak programmer changes a mutable field on the subclass */
mutable.field3=4;
/*
* Ahhh let me just print my immutable
* reference again because I can trust it
* so much.
*
*/
System.out.println(immutable.add());
/* Why is this buggy piece of crap printing 7 and not 3
It couldn't have changed its IMMUTABLE!!!!
*/
}
}
/* This class adheres to all the principles of
* good immutable classes. All the members are private final
* the add() method doesn't modify any state. This class is
* just a thing of beauty. Its only missing one thing
* I didn't declare the class final. Let the chaos ensue
*/
public class ImSoImmutable{
private final int field1;
private final int field2;
public ImSoImmutable(int field1, int field2){
this.field1 = field1;
this.field2 = field2;
}
public int add(){
return field1+field2;
}
}
/*
This class is the problem. The problem is the
overridden method add(). Because it uses a mutable
member it means that I can't guarantee that all instances
of ImSoImmutable are actually immutable.
*/
public class OhNoMutable extends ImSoImmutable{
public int field3 = 0;
public OhNoMutable(int field1, int field2){
super(field1, field2);
}
public int add(){
return super.add()+field3;
}
}
实际上,在依赖注入环境中遇到上述问题是很常见的。您没有显式实例化事物,并且给出的超类引用实际上可能是子类。
要解决的问题是,要坚决保证不变性,您必须将类标记为final。这在Joshua Bloch的Effective Java中进行了深入介绍,并在Java内存模型规范中明确引用。

TA贡献1757条经验 获得超8个赞
要使类在Java中不可变,可以注意以下几点:
1.不要提供setter方法来修改该类的任何实例变量的值。
2.将课程声明为“最终”。这将防止任何其他类对其进行扩展,从而阻止其覆盖任何可能修改实例变量值的方法。
3.将实例变量声明为private和final。
4.您还可以将类的构造函数声明为私有,并在需要时添加工厂方法来创建类的实例。
这些要点应该有帮助!!
添加回答
举报