如何在Java中创建不可变对象?
2022-08-31 12:00:18
如何在Java中创建不可变对象?
哪些对象应该称为不可变对象?
如果我的类包含所有静态成员,它是不可变的吗?
如何在Java中创建不可变对象?
哪些对象应该称为不可变对象?
如果我的类包含所有静态成员,它是不可变的吗?
以下是不可变对象的硬性要求。
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;
}
}
在实践中,在依赖关系注入环境中遇到上述问题是很常见的。你没有显式实例化事物,并且你被赋予的超类引用实际上可能是一个子类。
需要注意的是,要对不可变性做出硬保证,您必须将类标记为 。这在Joshua Bloch的 Effective Java 中有深入介绍,并在 Java 内存模型的规范中明确引用。final
只是不要将公共赋值器(setter)方法添加到类中。