接著上期繼續看本書高質量編碼建議7、8條的閱讀筆記
7.避免使用最終方法
此處所謂的終結方法指的就是finalize()方法,這個方法可能對於從C++轉向Java的新手感到混淆,因為在C++中有一個“析構函數”,析構函數所代表的意義就是在這個對象垃圾回收前所做的一些動作例如資源的關閉等。對於Java來說垃圾回收是自動的,或者稱之為不可預知或不可控,儘管finalize方法所代表的也是在垃圾回收前所做的一些動作,但對於GC的時間你不能掌握,也就是說不能保證finalize方法會被及時執行,這是很危險的,一般情況下這個方法不會被用到。
終結方法既然存在那它就並不是毫無用處,第一種用途就是充當一個“安全網”,終結方法“本該”是在GC前做一些清理動作,但GC的時間未知,也就是終結方法執行時間未知,對於FileInputStream類我們都知道應該在try-finally中對其調用close方法,但也許我們會忘記編寫此方法,在FileInputStream源代碼中就實現了終結方法目的就在於如果忘記了close方法,至少還有終結方法,雖然可能不能得到及時執行,但晚執行總比不執行好吧。第二個用途可能使用的場景就可能比較少,JVM只回收普通對象,對於本地對象(也就是不是Java實現的對象),JVM並不會對它進行回收,此時我們就可以在終結方法中對本地對象進行一些清理操作,但一定記住一定要是“不擁有關鍵資源的前提”,且在子類中重寫了終結方法一定要現實調用super.finalize(),否則父類的終結方法不會被調用。
綜上,對於終結方法,一般代碼中並不會使用,如果要使用一定要考慮上面兩種用途是否值得去做,萬萬不應該依賴終結方法來更新重要的持久狀態。
8.覆蓋equals時請遵守通用約定
對於equals方法,在編碼中最常用的可能就是比較兩個字符串是否是值相等的。需要自己重寫equals方法的場景可能並不是人人都能有幸碰到,而如果碰到了該怎麼辦,本條目下書中說明了重寫equals方法時需要遵守的一些通用約定,如果不遵守這些約定可能導致無法和其他類配合使用。
equals方法來自於Object類:
public boolean equals(Object obj){
return(this == obj)
}
可以看到在Object類中equals比較的兩個實例是否是引用相等的,換句話說,在不考慮“值相等”的情況下,每個實例都是獨一無二的,每個實例都只與它自身相等。何時需要重寫equals方法呢?頂級類只提供了引用是否相等,如果你需要自己實現一個邏輯是否相等,此時則需要重寫equals方法,例如String類,但當在重寫equals方法時,應該遵守以下約定:
自反性:對於任何非null的引用值x,x.equals(x)必須返回true。也就是說一個類的實例一定是與它本身相等的,不管你怎麼實現它的邏輯判斷,但它的“本”不能忘。
對稱性:對於任何非null的引用值x和y,當且僅當y.equals(x)返回true時,x.equals(y)必須返回true。這條比較好理解,x=1,y=1,你不能y=x而x!=y吧。
傳遞性:對於任何非null的引用值x、y和z,如果x.equals(y)返回true,並且y.equals(z)也返回true,那麼x.equals(z)也必須返回true。顯而易見。
一致性:對於任何非null的引用值x和y,只要equals的比較操作在對象中的所用的信息沒有被修改,多次調用x.equals(y)就會一致地返回true,或者一致地返回false。這條顯然,你不能多調用判斷幾次它的結果就產生變化了吧。
對於任何非null的引用值x,x.equals(null)必須返回null。
一定要反覆檢查測試自己重寫的equals方法是否遵守以上約定,否則程序可能會變得不正常,因為許多類,包括所有的集合類都依賴於是否遵守了equals約定。書中舉了詳細的例子來說明上述約定,這裡不再敘述。
我們來分析下String類中重寫的equals方法:
//String.equals
public boolean equals(Object anObject) {
if (this == anObject) { //是否等於自身
return true;
}
if (anObject instanceof String) { //類型是否相等
String anotherString = (String) anObject; //轉換類型
int n = value.length;
if (n == anotherString.value.length) { //先判斷長度是否相等
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) { //一個一個字符判斷值是否相等
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
String中equals方法的實現實際上就是書中給我們的重寫equals的一些訣竅:
1、使用==操作檢查“對象是否為這個對象的引用”,這不是必須的,只是作為一種性能優化,例如Integer類中並無此項判斷。
2、使用instanceof操作符檢查“參數是否為正確的類型”。
3、把參數轉換成正確的類型。
4、對於該類中的每個“關鍵”域,檢查參數中的域是否與該對象中對應的域想匹配。
看看我們的資料:4000G java,大數據,人工智能視頻資料提供您學習!
閱讀更多 JavaLeader 的文章