若是一个对象的状态在构造后不能改变,则该对象被认为是不可变的,对不可变对象的最大依赖被普遍认为是一种建立简单、可靠代码的合理策略。java
不可变对象在并发应用程序中特别有用,因为它们不能改变状态,所以它们不会被线程干扰破坏或在不一致的状态下观察。git
程序员一般不肯意使用不可变对象,由于他们担忧建立新对象的成本而不是就地更新对象的成本,对象建立的影响常常被高估,而且能够经过与不可变对象相关联的一些效率来抵消,这些包括因为垃圾收集而减小的开销,以及消除保护可变对象免于损坏所需的代码。程序员
如下小节采用其实例可变的类,并从中派生出具备不可变实例的类,经过这样作,它们为这种转换提供了通常规则,并演示了不可变对象的一些优势。github
SynchronizedRGB类定义了表示颜色的对象,每一个对象将颜色表示为表明主要颜色值的三个整数和一个给出颜色名称的字符串。segmentfault
public class SynchronizedRGB { // Values must be between 0 and 255. private int red; private int green; private int blue; 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 SynchronizedRGB(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 void set(int red, int green, int blue, String name) { check(red, green, blue); synchronized (this) { this.red = red; this.green = green; this.blue = blue; this.name = name; } } public synchronized int getRGB() { return ((red << 16) | (green << 8) | blue); } public synchronized String getName() { return name; } public synchronized void invert() { red = 255 - red; green = 255 - green; blue = 255 - blue; name = "Inverse of " + name; } }
必须当心使用SynchronizedRGB
以免在不一致的状态下被查看,例如,假设一个线程执行如下代码:并发
SynchronizedRGB color = new SynchronizedRGB(0, 0, 0, "Pitch Black"); ... int myColorInt = color.getRGB(); //Statement 1 String myColorName = color.getName(); //Statement 2
若是另外一个线程在语句1以后但在语句2以前调用color.set
,则myColorInt
的值将与myColorName
的值不匹配,为了不这种结果,必须将两个语句绑定在一块儿:函数
synchronized (color) { int myColorInt = color.getRGB(); String myColorName = color.getName(); }
这种不一致只适用于可变对象 — 对于不可变版本的SynchronizedRGB
,它不会是一个问题。this
如下规则定义了用于建立不可变对象的简单策略,并不是全部记录为“不可变”的类都遵循这些规则。这并不必定意味着这些类的创造者是草率的 — 他们可能有充分的理由相信他们类的实例在构造后永远不会改变,可是,这种策略须要复杂的分析,不适合初学者。线程
setter
”方法 — 修改字段或字段引用的对象的方法。final
和private
。final
,更复杂的方法是使构造函数为private
并在工厂方法中构造实例。若是实例字段包含对可变对象的引用,则不容许更改这些对象:code
将此策略应用于SynchronizedRGB
会致使如下步骤:
setter
方法,第一个方法set
,任意改变对象,在类的不可变版本中不存在,第二个方法invert
,能够经过让它建立一个新对象而不是修改现有对象来进行调整。private
,他们进一步得到final
。final
。在这些更改以后,咱们有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); } }