Reputation: 4563
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;
}
}
Upvotes: 5
Views: 13399
Reputation:
The class (Card
) is missing a proper implementation of equals(Object)
and hashCode()
Without both of these defined it will just not work. (It compiles fine because these methods are both virtual and inherited in all objects as they are part of Object: HashMap can't enforce this at compile-time.) See the links above for the contract that is required.
Both of these methods are required to be implemented because hashCode
determines the hash-bucket used in the HashMap implementation and equals
is to ensure that an object is value-equals (multiple objects can have the same hashCode
, which is why equals
is also required). See Hash table for more general hash details.
If these methods are not overloaded then the implementations defined in Object are used. That is, x.equals(y)
has near-x == y
semantics and hashCode
returns a stable number per contract. This effectively makes the map work like an identity map (when Card objects are keys): only the exact same object can retrieve a previously stored value -- every other get will return null, as observed.
Happy coding.
Upvotes: 13
Reputation: 50858
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.
Upvotes: 3
Reputation: 2173
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.
Upvotes: 1
Reputation: 22461
Card should override equals
and hashCode
.
Take a look here: http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html
Upvotes: 1
Reputation: 1536
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.
Upvotes: 2
Reputation: 22721
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.
Upvotes: 1