標籤:java類 不可變
不可變類:一旦建立,狀態無法改變
關於建立不可變類有很多規則,下面一一介紹這些規則:
目錄
- 定義不可變類的益處
- 定義不可變類指南
定義不可變的益處
- 構造簡單,便於測試和使用
- 不可變類自然是安全執行緒的,無需關心多線程和同步問題
- 不需要實現clone
- 可以消極式載入,緩衝它的傳回值
- 由於不可變可以用於Map的key和Set的元素(set元素不能重複)
- 當作為屬性時,不需要深度clone
如何讓類不可變
在Java文檔中,有關於如何定義不可變類指南: click here
- 不提供setter方法,setter方法用於修改屬性和對象引用
這個原則闡述了在你類定義的所有可變屬性中,不提供setter方法,setter方法意味著你能夠改變這個屬性的狀態。必須阻止提供setter方法
- 所有的屬性修飾添加private和final
這是另外一種增加不可變的方式,屬性聲明為private為了在類之外不能夠被訪問到,final修飾符為了讓你不能隨便的改變它們
- 不允許子類重寫方法
最簡單的方式聲明類為final,final類不允許被重寫
- 當屬性中存在可變物件變數時,要特別留意
永遠銘記你的物件變數,不是可變的就是不可變的(這句好像是廢話。。),識別出來可變對象,對可變對象的內容進行copy,並建立一個新對象賦值給它,這樣保證可變對象的不可變,通過直接copy對象內容的形式,保持資料不可變
來點優雅的,定義一個private的構造方法,通過 Factory 方法構造對象
只說太抽象,還是來點執行個體痛快
import java.util.Date;/*** Always remember that your instance variables will be either mutable or immutable.* Identify them and return new objects with copied content for all mutable objects.* Immutable variables can be returned safely without extra effort.* */public final class ImmutableClass{ /** * Integer class is immutable as it does not provide any setter to change its content * */ private final Integer immutableField1; /** * String class is immutable as it also does not provide setter to change its content * */ private final String immutableField2; /** * Date class is mutable as it provide setters to change various date/time parts * */ private final Date mutableField; //Default private constructor will ensure no unplanned construction of class private ImmutableClass(Integer fld1, String fld2, Date date) { this.immutableField1 = fld1; this.immutableField2 = fld2; this.mutableField = new Date(date.getTime()); } //Factory method to store object creation logic in single place public static ImmutableClass createNewInstance(Integer fld1, String fld2, Date date) { return new ImmutableClass(fld1, fld2, date); } //Provide no setter methods /** * Integer class is immutable so we can return the instance variable as it is * */ public Integer getImmutableField1() { return immutableField1; } /** * String class is also immutable so we can return the instance variable as it is * */ public String getImmutableField2() { return immutableField2; } /** * Date class is mutable so we need a little care here. * We should not return the reference of original instance variable. * Instead a new Date object, with content copied to it, should be returned. * */ public Date getMutableField() { return new Date(mutableField.getTime()); } @Override public String toString() { return immutableField1 +" - "+ immutableField2 +" - "+ mutableField; }}
驗證以上不可變類:
import java.util.Date;public class MainTest{ public static void main(String[] args) { ImmutableClass im = ImmutableClass.createNewInstance(100,"test", new Date()); System.out.println(im); tryModification(im.getImmutableField1(),im.getImmutableField2(),im.getMutableField()); System.out.println(im); } private static void tryModification(Integer immutableField1, String immutableField2, Date mutableField) { immutableField1 = 10000; immutableField2 = "test changed"; mutableField.setDate(10); }}
輸出結果如下:
100 - test - Tue Jun 09 23:14:01 CST 2015
100 - test - Tue Jun 09 23:14:01 CST 2015
從輸出中可以看出:即使通過對象引用改變物件變數,值依然不改變,因此類是不可變類
參考這裡:click here
涉及資料:click here
官方教程: click here
如何讓Java類不可變