Effective Java2-學習筆記 第11-20條

11.謹慎地覆蓋clone

  • 若是能夠用拷貝構造器或拷貝工廠代替

12.考慮實現Comparable接口

  • 值類存在很是明顯的內在排序關係,就應該堅定考慮實現這個接口
  • 保持和equals()的一致性
  • 當該對象小於,等於或大於指定對象的時候,分別返回一個負整數,零或者正整數.若是因爲指定對象的類型而沒法與該對象進行比較,則拋出ClassCastException異常
  • 若是非零差值不會溢出,則能夠直接return這個插值

13.使類和成員的可訪問性最小化

  • 儘量地使每一個類或者成員不被外界訪問
  • 若是你把它作成公有的,你就有責任永遠支持它,以保持它們的兼容性
  • 受保護的成員應該儘可能少用
  • 可讓測試做爲被測試的包的一部分來運行,從而可以訪問它的包級私有的元素
  • 若是域是非final的,或者是一個指向可變對象的final引用,那麼一旦使這個域成爲公有的,就放棄了對存儲在這個域中的值進行限制的能力,這意味着,你也放棄了域不可變的能力.同時,當這個域被修改的時候,你也失去了對它採起任何行動的能力.所以,包含公有可變域的類並非線程安全的.
  • 若是final域包含可變對象的引用,它即是final域的全部缺點.雖然引用自己不能被修改,可是它所引用的對象倒是能夠被修改-這會致使災難性的後果
  • 類具備公有的靜態final數組域,或者返回這種域的訪問方法,這幾乎老是錯誤的.若是類具備這樣的域或者訪問方法,客戶端將可以修改數組中的內容.這是安全漏洞的一個常見根源,解決:1.可使公有數組變成私有的,並增長一個公有的不可變列表  2.使數組變成私有的,並增添一個公有方法,它返回私有數組的一個備份

14.在公有類中使用訪問方法而非共有域

  • 若是公有類暴露了它的數據域,要想在未來改變其內部表示法是不可能的,由於公有類的客戶端代碼已經遍及各處了.
  • 若是類是包級私有的嵌套類,直接暴露它的數據域並無本質的錯誤-假設這些數據確實描述了改類所提供的抽象.
  • 在私有嵌套類的狀況下,改變的做用域範圍被進一步限制在外圍類中.
  • 若是不改變類的API,就沒法改變這種類的表示法.

15.使可變性最小

不可變的類比可變類更加易於設計,實現和使用.它們不容易出錯,且更加安全.編程

爲了使類更爲不可變,要遵循下面五條規則:數組

  1. 不要提供任何會修改對象狀態的方法.
  2. 保證類不會被擴展.
  3. 使全部的域都是final的.
  4. 使全部的域都成爲私用的.
  5. 確保對於任何可變組件的互斥訪問.
    • 若是類具備指向可變對象的域,則必須確保該類的客戶端沒法得到指向這些對象的引用.
    • 永遠不要用客戶端提供的對象引用來初始化這樣的域,也不要從任何訪問方法中返回該對象引用.
    • 在構造器,訪問方法和readObject方法中請使用保護性拷貝技術
  • 不可變對象本質上是線程安全的,它們不要求同步.
  • 不可變對象能夠被自由地共享,永遠也不須要進行保護性拷貝.
  • 不只能夠共享不可變對象,甚至也能夠共享它們的內部信息.
  • 不可變對象爲其餘對象提供大量的構件.
  • 不可變類真正惟一的缺點是,對於每一個不一樣的值都須要一個單獨的對象.

若是你執行一個多步驟的操做,而且每一個步驟都會產生一個新的對象,除了最後的結果以外其餘的對象最終都會被丟棄,此時性能問題就會顯露出來.緩存

  1. 解決,先猜想一下會常常用到哪些多步驟的操做,而後將它們做爲基本類型提供.若是某個多步驟操做已經做爲基本類型提供,不可變的類就能夠沒必要在每一個步驟單首創建一個對象.
  2. 解決,若是能精確地預測出客戶端將要在不一樣的類上執行哪些複雜的多階段操做,這種包級私有的可變配套類的方法就能夠工做的很好.若是沒法預測,最好的方法是提供一個公有的可變配套類.
  • 讓不可變的類編程final的另外一種方法就是,讓類的全部構造器都變成私有的或者包級私有的,並添加公有的靜態工廠來代替公有的構造器
    • 這種方法還使得有可能經過改善靜態工廠的對象緩存能力,在後續的發行版本中改進該類的性能.
    • 工廠的名字能夠清楚地代表它的功能.
  • 若是你在編寫一個類,它的安全性依賴於(來自不可信客戶端的)BigInteger或者BigDecimal參數的不可變性,就必須進行檢查,以肯定這個參數是否爲"真正"的BigInteger或者BigDecimal,而不是不可信子類的實例.若是是後者的話,就必須在假設它多是可變的前提下對它進行保護性拷貝
  • 除非有很好的理由要讓類成爲可變的類,不然就應該是不可變的.惟一的缺點是在特定的狀況下存在潛在的性能問題.
  • 所以,除非有使人信服的理由要使域變成是非final的,不然要使每一個域都是final的.
  • 構造器應該建立徹底初始化的對象,並創建起全部的約束關係.與所增長的複雜性相比,"從新初始化"方法一般並無帶來太多的性能優點.
相關文章
相關標籤/搜索