Why does this HashMap.get return a null?

12,327

Solution 1

It is indeed exactly because of this issue.

You need to define what equality means on cards, so you need to override the equals and hashCode methods.

If you do not, it assumes that two cards are only equal if they're the same instance. (As in the default behavior of equals.)

Note that, it is very important you override both equals and hashCode, as two objects that're equal must hash to the same value for a HashMap to work correctly.

For more information, see Overriding equals and hashCode in Java.

Solution 2

Maybe it's a similar quick like how the var1 == var2 are not equals unless they point to the > same Object in memory, instead you have to use the var1.equals(var2)

Almost. As you would expect, a hash map needs a way of getting hash codes for your objects. In Java, this is provided by the hashCode method which is implemented by Object, but needs to be overridden by your Card class.

*update: as pst points out, it must also reimplement equals.

Solution 3

You need to implement the hashCode and equals methods, since this allows equality testing on two different objects, and also helps with hash map storage. Without implementing these, two objects will be seen as distinct even if their properties are the same. See http://www.jchq.net/certkey/0902certkey.htm for more details.

Solution 4

Card should override equals and hashCode. Take a look here: http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html

Solution 5

You'll have to override the hashCode() method for Card and make it return the same value if and only if the cards are equal - you should override equals() too. Because that's what the HashMap relies on in order to find the objects referenced by the keys; as it stands now, it's the versions of those methods inherited from Object that are being used, which will only match if you use the same objects as keys, whereas you're creating new, albeit 'equal', ones.

Share:
12,327
ProfessionalAmateur
Author by

ProfessionalAmateur

Updated on June 22, 2022

Comments

  • ProfessionalAmateur
    ProfessionalAmateur about 2 years

    I'm trying to create a Hashmap to perform a lookup for me. However when I run this test code, the output is null. I think it has to due with the nature of how the keys are being stored, but Im not positive. Maybe it's a similar quirk like how the var1 == var2 are not equals unless they point to the same Object in memory, instead you have to use the var1.equals(var2)?

    There are two classes to test this.

    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;
        }   
    }
    
  • Admin
    Admin about 13 years
    It must also implement equals, per the contract.
  • Arjan
    Arjan about 13 years
    If equals() returns true, the hashCode() must be the same. If equals() returns false, the outcome of hashCode() still may be equal but also may differ. If the outcome of hashCode() differs, equals() must return false.
  • Steve Kuo
    Steve Kuo about 13 years
    This answer is incorrect in that two not equals objects can have the same hash code (ie, the statement that "if and only if the cards are equal " is incorrect). Arjan sums it up correctly.
  • entonio
    entonio over 11 years
    @SteveKuo so if I removed 'and only if' from what I wrote, the answer would no longer be incorrect, but your comments would cease making sense. What should I do?