優勢:html
印象比較深入的是:以前寫安卓用到了OkHttp,使用的OkHttp是用Kotlin寫的,其中實例化對象用的就是這個建造者模式,當時覺得是Kotlin鏈式調用的某種語法特性,後來才知道是設計模式java
主要用於多參數時,避免重疊構造器和避免無參構造器建立對象依次set參數過程當中JavaBean可能處於的不一致狀態git
Singleton常見實現方法:github
經過放射調用私有構造器,能夠修改構造器,建立第二個實例時拋出異常
序列化時除了實現 Serializable接口,還須要提供readResolve,防止反序列化建立新的實例設計模式
SOLID 原則中的 D 依賴反轉原則 (Dependency Inversion Principle),依賴注入是該原則的一種實現方式
建立一個新的實例時,就將該資源傳到構造器中數組
終結方法 (finalizer) 和 清除方法(cleaner JDK9) 都不可預測且會形成性能損失
注重時間的任務不該該使用這兩種方法來完成
不該該依賴這兩種方法來更新重要的持久狀態(好比:釋放共享資源,可能還沒開始釋放資源,系統就垮掉了)
TODO p25 終結方法攻擊(finalizer attack)
TODO 合理用途:緩存
實現了AutoCloseable 接口安全
不用覆蓋的狀況(知足其一便可)架構
覆蓋equals的通用規範ide
子類與父類 自反性和傳遞性的對立:沒法再拓張可實例化的類的同時,既增長新的值組件,同時又保留equals約定
IDEA 默認子類equals寫法就是:使用getClass() 比較對象,而後調用父類equals最後對比子類拓展的屬性
Stream 初始化Set:
private static final Set<Point> unitCircle = Stream.of( new Point(1, 0), new Point(0, 1), new Point(-1, 0), new Point(0, -1) ).collect(Collectors.toCollection(HashSet::new));
辨析:instanceof getClass()==
使用複合優於繼承:提供私有Point域以及共有視圖(view)方法
JDK反例:public class Timestamp extends java.util.Date,在同一個集合中使用或者其餘方式混合使用,可能有不正確的行爲
instanceof 第一個操做符爲null 那麼返回的必定爲false,使用instanceof能夠省略null判斷
一致性,不要使equals方法依賴於不可靠的資源,JDK反例:URL equals
高質量equals訣竅
注意點:
Object的hashCode方法爲native方法:public native int hashCode();
hashCode註釋提到:hashCode返回的是由對象存儲地址轉化獲得的值
As much as is reasonably practical, the hashCode method defined by class {@code Object} does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the Java™ programming language.)
若是沒有覆蓋hashCode致使兩個相同實例具備不一樣散列碼,HashMap有一項優化,能夠將每一個項相關聯的散列碼緩存起來,若是散列碼不匹配,不會校驗對象相等性
好的散列函數傾向於「爲不相等的對象產生不相等的散列碼」,每一個對象都被映射到同一個散列桶中,會實其退化爲鏈表
簡單解決方法:
使用31緣由:
計算機在進行數值運算的時候,是經過補碼錶示每一個數值的 正數原反補相同;負數反碼符號位不變,其它位都取反;負數的補碼在反碼的基礎上加1 Java 三種位運算(補碼) << 左移:丟棄最高位,0補最低位 >> 右移:符號位不變,左邊填充符號位 >>> 無符號右移:忽略了符號位,左邊填充0
Objects類:public static int hash(Object... values) 便捷,可是相對速度慢一些:可變參數引起數組建立,基本類型須要拆箱裝箱
不可變類用使用private 變量 緩存hash值, 延遲初始化(lazily initialize)
構造器爲:PhoneNumber(short areaCode, short prefix, short lineNum) ,必須強轉 (short)1
直接傳入整數,否者報錯,沒有int類型構造器
注意:
Object實現:類名稱@散列碼無符號十六進制表示
toString 返回對象中包含的全部值得關注的信息
能夠在文檔中指定返回的格式,並配套靜態工廠或者構造器,便於相互轉換,JDK例子:BigInteger、BigDecimal、包裝類
靜態工具類和大多數枚舉類編寫toString意義不大
記得實現Cloneable接口(空的interface),否者拋出異常:java.lang.CloneNotSupportedException
Object中的clone方法:protected native Object clone() throws CloneNotSupportedException;
TODO p46
實現Cloneable接口的類是爲了提供一個功能適當複雜的公有clone方法,它無需調用構造器就能夠建立對象
不變類永遠都不該該提供clone方法
Clone方法就是另外一個構造器;必須保證它不會傷害到原始對象,並確保正確地建立被克隆對象中的約束條件
若是域是final修飾,clone是禁止給final域賦值,Cloneable架構於引用可變對象的final域的正經常使用法是不相兼容的
線程安全:Object類 clone 沒有同步
實現了Cloneable接口的類
拷貝對象更好的方法是提供拷貝構造器和拷貝工廠
最佳實踐:用clone複製數組
Comparable接口:public int compareTo(T o);
將這個對象與指定對象比較,大於、等於、小於指定對象返回負整數、零和正整數,類型不匹配拋出RuntimeException:ClassCastException
通用約定
依賴比較關係的類有:TreeSet TreeMap Collections Arrays
與equals相同:沒法在用新的值組件拓展課實例化的類時,同時保持compareTo約定,除非放棄面向對象抽象優點;能夠經過組合方式實現Comparable接口的類增長值組件(提供「視圖」 view方法)
BigDecimal d1 = new BigDecimal("1.0"); BigDecimal d2 = new BigDecimal("1.00"); System.out.println(d1.equals(d2)); // false System.out.println(d1.compareTo(d2)); // 0 Set<BigDecimal> bigDecimals = new HashSet<>(); // equals 比較 bigDecimals.add(d1); bigDecimals.add(d2); System.out.println(bigDecimals); // [1.0, 1.00] Set<BigDecimal> treeSets = new TreeSet<>(); // compareTo 比較 treeSets.add(d1); treeSets.add(d2); System.out.println(treeSets); // [1.0]
注意Double和Float 使用compare比較而非 < >
Java7 提供了包裝類的靜態compare方法,建議在compareTo中使用
從關鍵域開始逐步比較全部域,某個域產生非零結果當即返回
Java 8 提供了Comparator接口,簡潔,可是要付出性能成本
private static final Comparator<PhoneNumber> COMPARATOR = comparingInt((PhoneNumber pn) -> pn.areaCode) .thenComparingInt((PhoneNumber pn) -> pn.prefix) .thenComparingInt((PhoneNumber pn) -> pn.lineNum); @Override public int compareTo(PhoneNumber pn) { return COMPARATOR.compare(this, pn); }
GitHub effective-java-3e-source-code
Effective Java - 豆瓣
java中instanceof和getClass()的做用
Initializing HashSet at the Time of Construction
Java Object.hashCode()源碼分析
通俗易懂的 Java 位操做運算講解
Java 位運算(移位、位與、或、異或、非)