java效能優化方案9——優化自定義hasCode()方法和equals()方法

kele2014發表於2017-12-16

9、優化自定義hasCode()方法和equals()方法
在不能使用EnumMap的情況下,至少也要優化 hashCode() 和 equals() 方法。一個好的 hashCode() 方法是很有必要的,因為它能防止對高開銷 equals() 方法多餘的呼叫。
在每個類的繼承結構中,需要容易接受的簡單物件。讓我們看一下jOOQ的 org.jooq.Table 是如何實現的?
最簡單、快速的 hashCode() 實現方法如下:
// AbstractTable一個通用Table的基礎實現:

@Override
public int hashCode() {

// [#1938] 與標準的QueryParts相比,這是一個更加高效的hashCode()實現
return name.hashCode();

}
name即為表名。我們甚至不需要考慮schema或者其它表屬性,因為表名在資料庫中通常是唯一的。並且變數 name 是一個字串,它本身早就已經快取了一個 hashCode() 值。
這段程式碼中註釋十分重要,因繼承自 AbstractQueryPart 的 AbstractTable 是任意抽象語法樹元素的基本實現。普通抽象語法樹元素並沒有任何屬性,所以不能對優化 hashCode() 方法實現抱有任何幻想。覆蓋後的 hashCode() 方法如下:
// AbstractQueryPart一個通用抽象語法樹基礎實現:

@Override
public int hashCode() {

// 這是一個可工作的預設實現。
// 具體實現的子類應當覆蓋此方法以提高效能。
return create().renderInlined(this).hashCode();

}
換句話說,要觸發整個SQL渲染工作流程(rendering workflow)來計算一個普通抽象語法樹元素的hash程式碼。
equals() 方法則更加有趣:
// AbstractTable通用表的基礎實現:

@Override
public boolean equals(Object that) {

if (this == that) {
    return true;
}

// [#2144] 在呼叫高開銷的AbstractQueryPart.equals()方法前,
// 可以及早知道物件是否不相等。
if (that instanceof AbstractTable) {
    if (StringUtils.equals(name,
        (((AbstractTable<?>) that).name))) {
        return super.equals(that);
    }

    return false;
}

return false;

}
首先,不要過早使用 equals() 方法(不僅在N.O.P.E.中),如果:
• this == argument
• this“不相容:引數
注意:如果我們過早使用 instanceof 來檢驗相容型別的話,後面的條件其實包含了argument == null。我在以前的部落格中已經對這一點進行了說明,請參考10個精妙的Java編碼最佳實踐。
在我們對以上幾種情況的比較結束後,應該能得出部分結論。比如jOOQ的 Table.equals() 方法說明是,用來比較兩張表是否相同。不論具體實現型別如何,它們必須要有相同的欄位名。比如下面兩個元素是不可能相同的:
• com.example.generated.Tables.MY_TABLE
• DSL.tableByName(“MY_OTHER_TABLE”)
如果我們能方便地判斷傳入引數是否等於例項本身(this),就可以在返回結果為 false 的情況下放棄操作。如果返回結果為 true,我們還可以進一步對父類(super)實現進行判斷。在比較過的大多數物件都不等的情況下,我們可以儘早結束方法來節省CPU的執行時間。
一些物件的相似度比其它物件更高。
在jOOQ中,大多數的表例項是由jOOQ的程式碼生成器生成的,這些例項的 equals() 方法都經過了深度優化。而數十種其它的表型別(衍生表 (derived tables)、表值函式(table-valued functions)、陣列表(array tables)、連線表(joined tables)、資料透視表(pivot tables)、公用表表示式(common table expressions)等,則保持 equals() 方法的基本實現。


相關文章