不可變對象的類即爲不可變類(Immutable Class)。Java平臺類庫中包含許多不可變類,如String、基本類型的包裝類、BigInteger和BigDecimal等。 html
不可變對象有不少優勢: java
能夠遵守如下幾點來編寫一個不可變類: 安全
import java.util.Date; /** * Planet是一個不可變類,由於當它構造完成以後沒有辦法改變它的狀態 */ public final class Planet { /** * 聲明爲final的基本類型數據老是不可變的 */ private final double fMass; /** * 不可變的對象屬性 (String對象不可變) */ private final String fName; /** * 可變的對象屬性. 在這種狀況下, 這個可變屬性只能被這個類改變。 * (在其它狀況下, 容許在原生類外部改變一個屬性是頗有意義的; * 這種狀況就是當屬性做爲其它地方建立的一個對象引用) */ private final Date fDateOfDiscovery; public Planet(double aMass, String aName, Date aDateOfDiscovery) { fMass = aMass; fName = aName; //建立aDateOfDiscovery的一個私有拷貝 //這是保持fDateOfDiscovery屬性爲private的惟一方式, 而且保護這個 //類不受調用者對於原始aDateOfDiscovery對象所作任何改變的影響 fDateOfDiscovery = new Date(aDateOfDiscovery.getTime()); } /** * 返回一個基本類型值. * * 調用者能夠隨意改變返回值,可是不會影響類內部。 */ public double getMass() { return fMass; } /** * 返回一個不可變對象 * * 調用者獲得內部屬性的一個直接引用. 因爲String是不可變的因此沒什麼影響 */ public String getName() { return fName; } // /** // * 返回一個可變對象 - 不是一個好的方式. // * // * 調用者獲得內部屬性的一個直接引用. 這一般很危險,由於Date對象既能夠 // * 被這個類改變也能夠被它的調用者改變.即,類再也不對fDate擁有絕對的控制。 // */ // public Date getDateOfDiscovery() { // return fDateOfDiscovery; // } /** * 返回一個可變對象 - 好的方式. * * 返回屬性的一個保護性拷貝.調用者能夠任意改變返回的Date對象,可是不會 * 影響類的內部.爲何? 由於它們沒有fDate的一個引用. 更準確的說, 它們 * 使用的是和fDate有着相同數據的另外一個Date對象 */ public Date getDateOfDiscovery() { return new Date(fDateOfDiscovery.getTime()); } /** * 測試方法 * @param args */ public static void main(String[] args) { Planet planet = new Planet(1.0D, "earth", new Date()); Date date = planet.getDateOfDiscovery(); date.setTime(111111111L); System.out.println("the value of fDateOfDiscovery of internal class : " + planet.fDateOfDiscovery.getTime()); System.out.println("the value of date after change its value : " + date.getTime()); }
運行結果以下: 測試
the value of fDateOfDiscovery of internal class : 1393943752205
the value of date after change its value : 111111111
因而可知Planet類的屬性fDateOfDiscovery在對象構造完成以後就沒有再改變。 spa
在《Effective Java》一書中, Joshua Bloch提出了一個強制性的建議 : 線程
"類應該是不可變的,除非有很好的理由讓它是可變的....若是一個類不能設計爲不可變的,也要儘量的限制它的可變性." 設計
BigDecimal從技術上講不是不可變的, 由於它沒有聲明爲final. code
不可變類最適合表示抽象數據類型(如數字、枚舉類型或顏色)的值。Java 類庫中的基本數據類型的包裝類(如Integer 、 Long 和 Float )都是不可變的,其它數字類型(如 BigInteger 和 BigDecimal )也是不可變的。表示複數或任意精度的有理數的類將比較適合設計爲不可變類。甚至包含許多離散值的抽象類型(如向量或矩陣)也很適合設計成不可變類,這取決於你的應用程序。 orm
另外一個適合用不可變類實現的好示例就是 事件 。事件的生命期較短,並且經常會在建立它們的線程以外的線程中消耗,因此使它們成爲不可變的是利大於弊。大多數 AWT 事件類都沒有 嚴格的 做爲不可變類來實現。一樣地,在 通訊系統的 組件間 進行 消息傳遞,將消息對象設計成不可變的是明智的。《Effective Java》 htm
http://www.ibm.com/developerworks/library/j-jtp02183/
http://www.javapractices.com/topic/TopicAction.do?Id=29
http://www.javaworld.com/article/2077362/core-java/mutable-or-immutable.html