如何在Java中创建不可变对象?

2022-08-31 12:00:18

如何在Java中创建不可变对象?

哪些对象应该称为不可变对象?

如果我的类包含所有静态成员,它是不可变的吗?


答案 1

以下是不可变对象的性要求。

  1. 使课程最终确定
  2. 使所有成员成为最终成员,显式设置它们,在静态块中或在构造函数中
  3. 将所有成员设为私有
  4. 没有修改状态的方法
  5. 要非常小心地限制对可变成员的访问(记住字段可能是,但对象仍然可以是可变的。在这些情况下,您应该这样做。finalprivate final Date imStillMutabledefensive copies

上课背后的原因非常微妙,经常被忽视。如果不是最终的,人们可以自由地扩展你的类,重写或行为,添加可变属性,然后提供他们的子类作为替代。通过声明类,您可以确保不会发生这种情况。finalpublicprotectedfinal

要查看实际问题,请考虑以下示例:

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


答案 2

只是不要将公共赋值器(setter)方法添加到类中。