2011-05-20 195 views
5

我正在嘗試創建一個Hashmap來爲我執行查找。但是,當我運行此測試代碼時,輸​​出爲空。我認爲這應該與鑰匙的存儲性質有關,但我並不積極。也許這是一個類似的怪癖,就像var1 == var2不等於它們,除非它們指向內存中的相同對象,而是必須使用var1.equals(var2)爲什麼這個HashMap.get返回null?

有兩個類來測試這個。

TestCard.java

import java.util.HashMap; 

public class TestCard { 

    // HashMap for SpecialK Lookup 
    private static HashMap<Card, Integer> specialKLookup = new HashMap<Card, Integer>(); 

    // Constructor 
    public TestCard(){ 
    } 

    public static void main(String[] args) { 
     Card[] cards = new Card[3]; 
     cards[0] = new Card((short)12, (short)0); 
     cards[1] = new Card((short)0, (short)1); 
     cards[2] = new Card((short)5, (short)2); 

     /* Build SpecialK Lookup HashMap. 
     * Ace of Spades = 0 
     * Ace of Hearts = 1 
     * Ace of Diamonds = 2 
     * Ace of Clubs = 3 
     * ... 
     * Two of Clubs = 51 
     */ 
     Integer specialKCounter = 0; 
     for(int i=12;i>=0;i--){ 
       for (int j=0;j<4;j++){ 
         specialKLookup.put(new Card((short)i, (short)j), specialKCounter++); 
       } 
     } 

     System.out.println(specialKLookup.get(cards[0])); 
    } 
} 

Card.java

public class Card{ 
    private short rank, suit; 

    private static String[] ranks = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace"}; 
    private static String[] suits = {"Spades", "Hearts", "Diamonds", "Clubs"}; 

    //Constructor 
    public Card(short rank, short suit){ 
     this.rank = rank; 
     this.suit = suit; 
    } 

    // Getter and Setters 
    public short getSuit(){ 
     return suit; 
    } 

    public short getRank(){ 
     return rank; 
    } 

    protected void setSuit(short suit){ 
     this.suit = suit; 
    } 

    protected void setRank(short rank){ 
     this.rank = rank; 
    } 
} 

回答

12

類(Card)丟失的equals(Object)hashCode()

一個正確的實施既沒有將它定義將只是不工作這些。 (它編譯得很好,因爲這些方法都是虛擬的,並且在所有對象中都是繼承的,因爲它們是Object的一部分:HashMap無法在編譯時強制執行此操作。)請參閱上面有關所需合約的鏈接。

這些方法都需要被執行,因爲hashCode確定在HashMap中實現中使用的散列的桶和equals是保證一個目的是數值等於(多個對象可以具有相同hashCode,這就是爲什麼equals也是必需的)。請參閱Hash table以獲取更一般的哈希詳細信息。

如果這些方法沒有被重載,那麼使用在Object中定義的實現。也就是說,x.equals(y)已經接近-x == y語義和hashCode返回每個合同的穩定數量。這有效地使得地圖工作像標識圖(當卡對象是密鑰時):只有完全相同的對象可以檢索先前存儲的值 - 每隔一個get將返回null,如觀察到的。

快樂編碼。

1

您需要實現hashCode和equals方法,因爲這允許在兩個不同的對象平等的測試,並且還有助於散列圖存儲。如果不實現這些,即使兩個對象的屬性相同,它們也會被視爲不同的對象。有關更多詳情,請參閱http://www.jchq.net/certkey/0902certkey.htm

2

也許這是一個類似的快速怎麼樣的VAR1 == VAR2不等於除非它們指向內存中的>同一個對象,相反,你必須使用var1.equals(VAR2)

幾乎。正如您所期望的那樣,哈希映射需要獲取對象的哈希代碼的方法。在Java中,這是由Object實現的hashCode method提供的,但需要由您的Card類覆蓋。

*更新:正如pst指出的那樣,它也必須重新實現等於。

+1

它還必須按合同執行「equals」。 – 2011-05-20 22:36:23

3

確實是因爲這個問題。

您需要定義卡上的平等含義,因此您需要覆蓋equalshashCode方法。

如果你不這樣做,它假設兩張卡片只有相同的實例才相等。 (如在equals默認行爲。)

需要注意的是,這是你會覆蓋equalshashCode,作爲兩個對象that're等於必須散列爲相同的值的HashMap正常工作非常重要。請參閱Overriding equals and hashCode in Java

1

對於Card,您必須覆蓋hashCode()方法,並且當且僅當卡片相等時才返回相同的值 - 您也應該覆蓋equals()。因爲這就是HashMap爲了找到鍵引用的對象所依賴的東西;現在,它是從Object繼承的那些正在使用的方法的版本,只有當您使用相同的對象作爲鍵時纔會匹配,而您正在創建新的,儘管「相等」的。

+1

如果'equals()'返回true,則'hashCode()'必須相同。如果equals()返回false,hashCode()的結果仍然可能相等,但也可能不同。如果'hashCode()'的結果不同,'equals()'必須返回false。 – Arjan 2011-05-20 22:41:25

+0

這個答案不正確,因爲兩個不等於對象可以具有相同的哈希碼(即,「當且僅當卡相等」的說法不正確)。 Arjan正確地總結它。 – 2011-05-21 02:25:26

+0

@SteveKuo所以如果我刪除了'只有'從我寫的東西',答案將不再是不正確的,但你的意見將停止合理。我該怎麼辦? – entonio 2013-02-18 21:58:49