I am trying to locate a key in a HashMap. I can print the selected key by using \'get\' but when I use \'containsKey\' in an if statement, it is not found.
I KNOW
In Location class, make sure you are overriding hashCode and equals methods.
If you are, can you post them?
To avoid problems, your equals()
and hashCode()
methods should be consistent and conform to the requirements (as noted elsewhere).
Additionally, hashCode() should not rely on mutable members, otherwise your calculated hash code can change, and this affects the internal workings of the HashMap
. That will reveal itself in an inability to retrieve stuff from Hash*
collections.
Both get()
and containsKey()
are using the Location
class's hashCode()
method. The equals()
method isn't called unless there is a hash collision. (thus, HashMap's get() won't use equals()
in every situation.)
For your Location
class, did you by chance happen to implement your own version of hashCode()
? The hashCode()
method should be implemented carefully. Joshua Bloch described all the details in the book Effective Java, portions of which are online... I'll go find the link to those sample chapters: Effective Java Sample Chapters. You want chapter 3.
As I asked in the comment to the question, Where does your _levels
variable come from? I don't see it declared inside that method and your naming (underscore prefix, are you importing that convention from some other language?) suggests that it "lives" outside this method. Perhaps other code is changing it during execution? Please let us know when you solve it; the suspense is killing me.
containsKey uses the method equals to compare the param with the entries in the key set. So the Location class needs to have a equals method that is good. The default equals method in java.lang.Object only returns true when both objects are the same object. In this case you probably have 2 different instances that needs to be compared and need a custom equals method.
You must ensure that the Location
class has properly implemented its hashCode()
and equals(Object)
methods (documentation). That is, if two Location
objects are effectively equal, they should share a common hash code and their equals
method should return true
.
The only thing I can think of that will cause this is if the state of supportingLocation
is somehow being mutated between the get(...)
call and the containsKey(...)
.
Assuming the code snippet you posted is the exact code that's causing problems, the only place this could occur is if one of Location#getZ(...)
, Location#hashCode()
or Location#equals(Object)
mutates the state of Location (or the Location constructor, or one of these methods starts a thread that randomly changes the state of the Location instance, but I think we can rule that out).
Could you verify that none of the methods above are changing the state of the supportingLocation
instance? While I am not familiar with the Location
class itself, I'd venture to guess that a class like that would ideally be immutable.
Edit:
To clarify, when I say that Location#getZ()
etc aren't mutating the Location, what I mean is:
Location x = new Location(1,2,3);
Location y = new Location(1,2,3);
boolean eq1 = x.equals(y);
int hash1 = x.hashCode();
x.getZ(); // this should *not* mutate the state of x
boolean eq2 = x.equals(y);
int hash2 = x.hashCode();
In the end, eq1 should be equal to eq1, and hash1 should be equal to hash2. If this is not the case, getZ() is mutating the state of x (or equals, or hashCode, or worse, those methods are completely off), and will result in the behavior you observed.