Documentation

The Java™ Tutorials
Hide TOC
A Strategy for Defining Immutable Objects定义不可变对象的策略
Trail: Essential Java Classes
Lesson: Concurrency
Section: Immutable Objects不变对象

A Strategy for Defining Immutable Objects定义不可变对象的策略

The following rules define a simple strategy for creating immutable objects. 以下规则定义了创建不可变对象的简单策略。Not all classes documented as "immutable" follow these rules. 并非所有记录为“不可变”的类都遵循这些规则。This does not necessarily mean the creators of these classes were sloppy — they may have good reason for believing that instances of their classes never change after construction. 这并不一定意味着这些类的创建者很马虎—他们可能有充分的理由相信他们的类的实例在构建之后永远不会改变。However, such strategies require sophisticated analysis and are not for beginners.然而,这些策略需要复杂的分析,不适合初学者。

  1. Don't provide "setter" methods — methods that modify fields or objects referred to by fields.不要提供“setter”方法—修改字段或字段引用的对象的方法。
  2. Make all fields final and private.将所有字段设置为final字段和private字段。
  3. Don't allow subclasses to override methods. 不允许子类重写方法。The simplest way to do this is to declare the class as final. 最简单的方法是将类声明为finalA more sophisticated approach is to make the constructor private and construct instances in factory methods.一种更复杂的方法是使构造函数private,并在工厂方法中构造实例。
  4. If the instance fields include references to mutable objects, don't allow those objects to be changed:如果实例字段包括对可变对象的引用,则不允许更改这些对象:
    • Don't provide methods that modify the mutable objects.不要提供修改可变对象的方法。
    • Don't share references to the mutable objects. 不要共享对可变对象的引用。Never store references to external, mutable objects passed to the constructor; if necessary, create copies, and store references to the copies. 永远不要存储对传递给构造函数的外部可变对象的引用;如有必要,创建副本并存储对副本的引用。Similarly, create copies of your internal mutable objects when necessary to avoid returning the originals in your methods.类似地,在必要时创建内部可变对象的副本,以避免在方法中返回原始对象。

Applying this strategy to SynchronizedRGB results in the following steps:将此策略应用于SynchronizedRGB将导致以下步骤:

  1. There are two setter methods in this class. 这个类中有两个setter方法。The first one, set, arbitrarily transforms the object, and has no place in an immutable version of the class. 第一个set任意变换对象,在类的不变版本中没有位置。The second one, invert, can be adapted by having it create a new object instead of modifying the existing one.第二个是invert,它可以通过创建新对象而不是修改现有对象来进行调整。
  2. All fields are already private; they are further qualified as final.所有领域都是private;他们还获得了final资格。
  3. The class itself is declared final.类本身被声明为final
  4. Only one field refers to an object, and that object is itself immutable. 只有一个字段引用一个对象,而该对象本身是不可变的。Therefore, no safeguards against changing the state of "contained" mutable objects are necessary.因此,没有必要对更改“包含的”可变对象的状态进行保护。

After these changes, we have ImmutableRGB:在这些更改之后,我们有了ImmutableRGB

final public class ImmutableRGB {

    // Values must be between 0 and 255.
    final private int red;
    final private int green;
    final private int blue;
    final private String name;

    private void check(int red,
                       int green,
                       int blue) {
        if (red < 0 || red > 255
            || green < 0 || green > 255
            || blue < 0 || blue > 255) {
            throw new IllegalArgumentException();
        }
    }

    public ImmutableRGB(int red,
                        int green,
                        int blue,
                        String name) {
        check(red, green, blue);
        this.red = red;
        this.green = green;
        this.blue = blue;
        this.name = name;
    }


    public int getRGB() {
        return ((red << 16) | (green << 8) | blue);
    }

    public String getName() {
        return name;
    }

    public ImmutableRGB invert() {
        return new ImmutableRGB(255 - red,
                       255 - green,
                       255 - blue,
                       "Inverse of " + name);
    }
}

Previous page: A Synchronized Class Example
Next page: High Level Concurrency Objects