建立和銷燬對象
NO.1 考慮用靜態工廠方法代替構造函數html
靜態工廠方法好處:
(1)構造函數有命名的限制,而靜態工廠方法有本身的名字,更加易於理解。
(2)靜態工廠方法沒必要在每次調用它們的時候建立一個新的對象。這種作法對於一個要頻繁建立相同對象的程序來講,能夠極大的提升性能。它使得一個類能夠保證是一個singleton;他使非可變類能夠保證「不會有兩個相等的實例存在」。java
java內存分紅4塊,一塊是堆,用來存放new的對象,一個是棧,用來存放局部變量,而後就是靜態變量區,存放常量,靜態變量,以及代碼區,存放代碼,因此很說靜態變量區是和堆棧並列的,並不從屬的。android
(3)靜態工廠方法在選擇返回類型時有更大的靈活性。使用靜態工廠方法,能夠經過調用方法時使用不一樣的參數建立不一樣類的實例,還能夠建立非公有類的對象,這就封裝了類的實現細節。
(4)在建立參數化類型實例的時候,他們使代碼變的更加簡潔。
例如:緩存
public static Boolean valueOf(boolean f){ return b ? Boolean.TRUE : Boolean.FALSE; } Map<String,List<String>> m=HashMap.newInstance();
靜態工廠方法的主要缺點在於類若是不含公有的或者受保護的構造器,就不能被子類化。靜態工廠方法的第二個缺點在於它們與 其餘的靜態方法實際上沒有任何區別,咱們須要遵照標準的命名習慣彌補這一劣勢,例如valueOf、of、getInstance、 newInstance、getType、newType。
NO.2 遇到多個構造器參數時要考慮用構建器安全
當有多個構造方法,通常是參數大於4個的時候,建議使用Builder模式。Builder模式既能保證像重疊構造器模式那樣的安全性,也能保證像JavaBean模式那麼好的可讀性。性能優化
NO.3 用私有構造器或者枚舉類型強化Singleton屬性ide
NO.4 經過私有構造器強化不可實例化的能力函數
在面向對象程序設計中,假如存在太多隻有靜態屬性和靜態方法的類;那麼,面向對象的思想可能在這會損失殆盡。工具
可是,並不能說面向對象的程序中就不該該出現只有靜態屬性和靜態方法的類,相反,有時候咱們還必須寫這樣的類做爲工具類。這樣的類怎麼實現呢?有人 可能會把該類定義成抽象類(Abstract class),的確,抽象類是不能夠實例化的,可是別忘了還有繼承,繼承了抽象類的子類在實例化時候,默認是會先調用父類無參數的構造函數的 super();,這時候,父類不是也被實例化了嘛?性能
其實咱們能夠這樣作,把該類的構造函數定義爲私有的(private),而類的內部又不調用該構造函數的話,就成功了。這樣帶來的後果就是該類成了 final的,不可能再被任何類繼承了,要被繼承,得提供一個公有(public)的或者保護(protect)的構造函數,這樣才能被子類調用。
public class UtilityClass { //Suppress default constructor for noninstantiability. private UtilityClass() { throw new AssertionError(); } }
這樣定義以後,該類將不會再被外部實例化了,不然會產生編譯錯誤。然而這樣的定義帶來的最直接的負面影響是該類將不能再被子類化。
NO.5 避免建立沒必要要的對象
若是一個對象是不可變的,那麼他老是能夠被重用的,如:
//不推薦,」test」原本就是一個String實例,若是此方法在一個循環中或者被頻繁的調用,將會嚴重影響性能。
String s = new String("test");
//推薦方式
String s = "test";
因爲String被實現爲不可變對象,JVM底層將其實現爲常量池,既全部值等於」test」的String對象實例共享同一對象地址,並且還能夠保證,對於全部在同一JVM中運行的代碼,只要他們包含相同的字符串字面常量,該對象就會被重用。
對於提供靜態方法和構造函數的非可變類,推薦使用靜態方法,這樣能夠避免重複建立對象,如:Boolean.vauleOf(String)方法優於構造函數Boolean(String)
類初始化的順序: 先初始化父類的靜態代碼 —> 初始化子類的靜態代碼 —> 初始化父類的非靜態代碼 —> 初始化父類構造函數
—> 初始化子類非靜態代碼 —>初始化子類構造函數。
NO.6 消除過時的對象引用
內存泄漏問題:若是一個對象的引用被無心識的保留起來,那麼垃圾回收機制是不會去處理這個對象,並且也不會去處理被這個對象引用的其它對象。 好比堆棧的彈出棧元素方法。
public Object pop(){ if(size == 0){ throw new EmptyStackException(); } Object result = elements[--size]; //自減後把原來的引用置爲null elements[size] = null; return result; }
內存泄露常出如今:
(1)類是本身管理內存。
(2)緩存,因爲緩存沒有及時清除無用的條目而出現,可使用weakHashMap來避免這種狀況
(3)監聽器和其餘回調,確保回調當即被當作垃圾回收的最佳方法是隻保留它們的弱引用(weak reference).
Java回調機制:A發送消息給B,B處理好A要求的事情後,將結果返回給A,A再對B返回的結果來作進一步的處理。
清理過時對象引用的好處是:若是在之後又被使用到該引用,最會拋下NullPointException而不是讓程序繼續錯誤的運行下去,儘量早的監測出程序中的錯誤老是有好處的。
方法:從新使用這個已經指向一個對象的引用,或結束其生命週期。
NO.7 避免使用終結方法
對於全部對象都通用的方法
NO.8 覆蓋equals時請遵照通用約定
(1) equals方法通常用於「值類」的情形,好比Integer,Date,目的是爲了比較兩個指向值對象的引用的時候,但願它們的邏輯是否相等而不是它們是否指向同一個對象。
約定:
a. 自反性 對任意的對象必須和它自身相等。對值引用x x.equals(x) 必定返回true
b. 對稱性 對任意的值引用x,y,若是x.equals(y) 必定有y.equals(x)
c. 傳遞性 對任意的值引用x,y,z,若是x.equals(y),y.equals(z) 必定有x.equals(z)
d. 一致性 對於任何非null的引用x和y,只要equals的比較操做在對象中所用的信息沒有被修改,屢次調用x.equals(y)就會一致地返回true
實現高質量equals方法的訣竅:
(1)使用==操做符檢查」參數是否爲這個對象的引用」。
(2)使用instanceof操做符檢查」參數是否爲正確的類型」,若是不是,則返回false。
(3)把參數轉換成爲正確的類型。
(4)對於該類中的每一個」關鍵」域,檢查參數中的域是否與該對象中對應的域相匹配。
@Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof MyType)) return false; MyType myType = (MyType)o; return objField.equals(o.objField) && intField == o.intField && Double.compare(doubleField,o.doubleField) == 0 && Arrays.equals(arrayField,o.arrayField); }
NO.9 覆蓋equals時總要覆蓋hashCode
相等的對象必需要有相等的散列碼,若是違反這個約定可能致使這個類沒法與某些散列值得集合結合在一塊兒使用,因此在改寫了equals方法的同時必定要重寫hashCode方法以保證一致性。
@Override public int hashCode() { int result = 17; result = 31 * result + areaCode; result = 31 * result + prefix; result = 31 * result + lineNumber; return result; }
NO.10 始終要覆蓋toString
toString返回值中包含全部信息
NO.11 謹慎地覆蓋clone
NO.12 考慮實現Comparable接口
java.lang.Comparable 接口
類和接口
NO.13 使類和成員的可訪問性最小
信息隱藏是軟件程序設計的基本原則之一,面向對象又爲這一設計原則提供了有力的支持和保障。優點:
(1)更好的解除各個模塊之間的耦合關係
(2)最大化並行開發
(3)性能優化和後期維護
(4)代碼的高可複用性
NO.14 在公有類中使用訪問方法而非公有域
若是類能夠在它所在的包的外部進行訪問,就提供訪問方法,以保留未來改變該類的內部表示方法的靈活性。
若是類是包級私有的,或者私有的嵌套類,直接暴露他的數據域並無本質的錯誤。由於這些代碼被限定在包中或外圍類中。
NO.15 使可變性最小化
使類成爲不可變類應遵循如下五條原則:
(1)不要提供任何會修改對象狀態的方法
(2)保證類不會被擴展,即聲明爲final類,或將構造函數定義爲私有
(3)使全部的域都是final的
(4)使全部的域都成爲私有的
(5)確保對於任何可變組件的互斥訪問。
不可變對象本質上是線程安全的,他們不要求同步。不可變對象能夠自由地共享。
NO.16 複合優先於繼承
NO.17 要麼爲繼承而設計,並提供文檔說明,要麼就禁止繼承
NO.18 接口優先於抽象類
(1)一個類只能繼承一個抽象類,而一個類卻能夠實現多個接口。
(2)抽象類能夠有構造方法,子類經過構造方法鏈調用構造方法,但不能實例化;接口沒有構造方法,不能實例化。
(3)實現接口的類必須實現接口的全部方法,而抽象類不須要。
(4)抽象類是對一種事物的抽象,即對類抽象,而接口是對行爲的抽象。
深刻理解Java的接口和抽象類
NO.19 接口只用於定義類型
接口不該該被用來導出常量。
NO.20 類層次優於標籤類
NO.21 用函數對象表示策略
NO.22 優先考慮靜態成員類
在Java中嵌套類主要分爲四種類型,下面給出這四種類型的應用場景。
(1)靜態成員類,靜態嵌套類:
static嵌套類經過寫出封裝的類名來進行實例化和訪問其內部成員:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
(2)非靜態成員類,成員內部類:
OuterClass outerObject=new OuterClass(); OuterClass.InnerClass innerObject = outerObject.new InnerClass();
(3)匿名類,匿名內部類:
匿名內部類就是沒有名字的局部類。它不使用關鍵字class, extends,implements以及構造函數。它一般做爲方法的一個參數傳入,好比在android開發中對一個Button添加一個OnClickListener
監聽器。匿名內部類隱匿的繼承了一個父類或者實現了一個接口。 (4)局部類,局部內部類: 定 義在方法內部的類叫做「局部內部類」。它的做用域僅限於方法做用域內,只能在方法的做用域內定義和實例化,是用處最小的類類型。和局部變量同樣,它不能被 修飾爲private, public, protected和static的,而且只能訪問方法內部定義的final變量。