若是一個對象的狀態在構造後不能改變,則該對象被認爲是不可變的,對不可變對象的最大依賴被普遍認爲是一種建立簡單、可靠代碼的合理策略。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); } }