2017-10-16 51 views
0

約書亞·布洛克說,在有效的Java:重寫的hashCode()方法

你必須在每一個重寫的equals類重載hashCode()()。 如果不這樣做將違反Object.hashCode()的一般合同 ,這將阻止您的類與所有基於散列的集合(包括 HashMap,HashSet和Hashtable)一起正常運行 。

我重寫equals()方法實現了模糊分數算法比較Match對象:

public class Match { 

    private String homeTeam; 

    private String awayTeam; 

    public Match(String homeTeam, String awayTeam) { 
     this.homeTeam = formatTeamName(homeTeam); 
     this.awayTeam = formatTeamName(awayTeam); 
    } 
} 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 
     Match that = (Match) o; 

     final int threshold = 6; 

     return (computeFuzzyScore(this.homeTeam, that.awayTeam) <= threshold || computeFuzzyScore(this.awayTeam, that.homeTeam) <= threshold) && 
        computeFuzzyScore(this.homeTeam, that.homeTeam) > threshold && computeFuzzyScore(this.awayTeam, that.awayTeam) > threshold; 

    } 

    // formatTeamName(), computeFuzzyScore() have been left out for brevity. 
} 

這樣,這些對象是相等的:

Match match0 = new Match("Man.City", "Atl.Madryt"); 
Match match1 = new Match("Manchester City", "Atlético Madryt"); 

我應該如何重寫hashCode()方法來產生相同的值對於這樣的對象?

+2

'match0'和'match'不一樣,是不是他們。所以他們應該最優地不具有相同的'hashCode()'。 'equals()'也不應該返回'true'。 –

+1

您應該在散列碼文檔中發現哈希碼對於等效實例應該是相同的,但可以是不同的哈希碼。這意味着哈希碼只能使用「equals」中使用的變量。 – AxelH

+0

也許這不是一個好主意,使用'equals'的這種實現。你打算只在你的自定義代碼中使用這個「equals」實現,還是你期望標準的JDK類調用你的'equals'方法? – Eran

回答

2

正如M.樂魯特和AxelH已經說出答案,等於應僅用於那些對象返回true相同(應該可以隨時切換並在代碼中呈現相同的結果,而不管使用哪個結果)。

解決此問題的一種方法是使用包裝類,在Remove duplicates from a list of objects based on property in Java 8的答案中描述。 你這樣做,包裝類只存儲計算出來的模糊值並比較和使用equals和hashcode中的值,然後你可以使用unwrapp來獲得真實值。

另一種方法是不喜歡yshavit說,做一套等於類似字符串:equalsIgnoreCase

+0

我對Match.equals()方法進行了嚴格的處理,並提出了另一種方法Match.isSimilarTo()進行模糊比較。 – TheChosenOne

+0

聽起來像是一個很好的解決方案。 – Jotunacorn

0

重要的部分是,如果match1 == match2 then match1.hashCode() == match2.hashCode()。比方說,你有一個數據庫,你用一個ID(一個數字)存儲匹配,那麼你可以讓hashCode返回id並完成。

不使用數據庫跟蹤您可以完成的匹配ID 爲每個團隊分配一個固定長度的數字ID並連接兩個ID作爲hashCode的結果。

作爲一個例子,"Manchester City"團隊可以是團隊1"Atlético Madryt"團隊2。如果散列長度爲32位,則可以使第一個16位爲團隊1,最後16位爲團隊2,如此表示。

// 16 bit for team 1 + 16 bit for team 2 
0000000000000001  0000000000000010 

的,這是一個有效的32位整數,將匹配的match1 == match2規則然後match1.hashCode() == match2.hashCode()

+0

爲每個實例添加'id'將會起作用,但是然後'Map'會爲每個實例創建一個桶(基本上,因爲它使用哈希碼來命令它的桶)。 – AxelH

1

我會建議你使用其他一些方法的名稱,如fuzzyEquals而不是equals。就其使用情況而言,您應該查看hashCodeequals。許多Java類(如HashMap)在未經您的同意的情況下調用這兩種方法,並要求它們嚴格遵守它們的想法。他們的想法不是你想要的,而是他們需要的。這件事情是這樣的:

  • 等於= homeTeam.equals & & awayTeam.equals
  • 的hashCode = homeTeam.hashCode^awayTeam.hashCode

通過重命名,你(一)保持HashMap和他的朋友高興,(b)避免混淆,(c)提高可讀性,(d)針對兩種不同的事物有兩種不同的方法,您可以獨立使用或進一步合併。

1

爲了完整,您應該查看數據模型。這是目前失敗的人

  • A Match介於兩個Team之間。
  • Team具有name
  • Team具有alias(0..N)。

你將不得不somethink這樣的:

public Team{ 

    private final String name; 
    private List<String> alias; 

    public Team(Sting name){ ... } 

    public boolean equals(Object obj){ 
     // check name 
    } 

    public int hashCode(){ 
     // hash the name 
    } 
} 

然後,只需查看Match來使用這個類的方法相同。

Team可以提供一種方法來檢查匹配String任何別名,如果不匹配/在alias發現,它將與name使用算法中檢查。如果alias匹配,則將其添加到List以進行未來研究。

這樣,你不需要每次運行你的模糊算法。如果你想讓用戶獲得匹配他選擇的任何輸入的Team,這可能是有用的。

相關問題