Java Forum / General / July 2006
How HashMap performs a get?
andrew.tanenbaum@katamail.com - 19 Jul 2006 11:57 GMT Hi, I have a problem with a HashMap. I store a couple key-value of type MyClass-Integer, but when I try to get the value, it returns null, even if the keys seem equal. For example, suppose that MyClass has an attribute called "name", which value is passed in the constructor, if I do something like:
MyClass obj1 = new MyClass("MyName"); myHashMap.put(obj1, 1);
MyClass obj2 = new MyClass("MyName"); Integer value = myHashMap.get(obj2);
It should return something, and not null. My question is, how a hashmap verifies if it contains the key "obj2"? I suppose that it invokes the method "equals" of the class MyClass. So, if I redefine the "equals" method in this way
public boolean equals(Object o){ if(o instanceof MyClass) return name.equals(((MyClass)o).getName()) else return super.equals(o); }
it should works? Or not?
Thanks
Matt Humphrey - 19 Jul 2006 12:06 GMT > Hi, I have a problem with a HashMap. I store a couple key-value of type > MyClass-Integer, but when I try to get the value, it returns null, even [quoted text clipped - 19 lines] > return super.equals(o); > } Yes, you must redefine equals, but you must also provide a compatible definition of hashCode(). Hashing uses the hash code as a first, very fast approximation. Two keys that are equal must produce the same hash code, although other keys can sometimes produce the same code.
Check out the details here http://mindprod.com/jgloss/hashcode.html#EQUALS
Cheers, Matt Humphrey matth@ivizNOSPAM.com http://www.iviz.com/
Ed - 19 Jul 2006 12:13 GMT andrew.tanenbaum@katamail.com skrev:
> My question is, how a hashmap verifies if it contains the key "obj2"? I > suppose that it invokes the method "equals" of the class MyClass. So, > if I redefine the "equals" method in this way See: http://www.geocities.com/technofundo/tech/java/equalhash.html
.ed
-- www.EdmundKirwan.com - Home of The Fractal Class Composition.
Download Fractality, free Java code analyzer: www.EdmundKirwan.com/servlet/fractal/frac-page130.html
Thomas Fritsch - 19 Jul 2006 12:38 GMT > Hi, I have a problem with a HashMap. I store a couple key-value of type > MyClass-Integer, but when I try to get the value, it returns null, even [quoted text clipped - 19 lines] > return super.equals(o); > } Please make sure that MyClass has a hashCode() method consistent with your equals() method. Something simple like this will probably work: public int hashCode() { return name.hashCode(); } You'll find the requirements in the API doc of Object#hashCode.
> it should works? Or not?
 Signature Thomas
andrew.tanenbaum@katamail.com - 19 Jul 2006 12:53 GMT Thomas Fritsch ha escrito:
> Please make sure that MyClass has a hashCode() method consistent with > your equals() method. Something simple like this will probably work: > public int hashCode() { > return name.hashCode(); > } Thanks to all, I overrided the hashCode method exactly like you said, the hashmap still doesn't work :-), I have to find where is the problem, in any case now I have all the necessary knolwedge about how hashmaps work
Alexander - 19 Jul 2006 13:37 GMT > Thanks to all, I overrided the hashCode method exactly like you said, > the hashmap still doesn't work :-), I have to find where is the > problem, in any case now I have all the necessary knolwedge about how > hashmaps work As far as I can see HashMap.get() does not only call the hashCode() method of the objects, but also equals(). Hence your class should probably not base its equals() results on actual instances but rather on the hashCode() values.
Alexander
Morten Alver - 20 Jul 2006 09:38 GMT >> Thanks to all, I overrided the hashCode method exactly like you said, >> the hashmap still doesn't work :-), I have to find where is the [quoted text clipped - 5 lines] > probably not base its equals() results on actual instances but rather on > the hashCode() values. No, that is wrong. The hashCode() method is not required to return equal values only for equal objects. Using String's hashCode() method different Strings can return the same value from hashCode(). Your equals() method must compare the instances. You can say that equals() is a stronger test than hashCode().
 Signature Morten
Alexander - 20 Jul 2006 10:19 GMT > No, that is wrong. The hashCode() method is not required to return equal > values only for equal objects. Using String's hashCode() method > different Strings can return the same value from hashCode(). Your > equals() method must compare the instances. You can say that equals() is > a stronger test than hashCode(). equals() is not stronger than hashCode() as this always depends on the implementation. String's hashCode() method actually uses the string data to compute its hashcode and so it is not extremely likely that different strings come out with the same hashcode (certainly it is possible as with most hash methods).
My comment however was not in regard to string methods, but certainly in context to MyClass. Hence it is actually correct, that equals() should not only base its result on its object instances, but rather on the common denominator of MyClass - which is the "name" member in this case.
Alexander
Patricia Shanahan - 20 Jul 2006 13:48 GMT >> Thanks to all, I overrided the hashCode method exactly like you said, >> the hashmap still doesn't work :-), I have to find where is the [quoted text clipped - 5 lines] > probably not base its equals() results on actual instances but rather on > the hashCode() values. By "the hashCode() values" do you mean the fields that are used to calculate the hash code, or the results it returns?
If the latter, you are just plain wrong, because equals is likely to need to distinguish more than 2^32 distinct values. For example, there are more than 2^32 sequences of 7 letters from a 26 letter alphabet. There are going to be instances of MyClass that have the same hashCode, but that equals should treat as being different.
If you just mean that equals and hashCode should be based on the same set of fields, I agree, but I think your wording suggests a backwards approach to designing them. Equality is the real issue. The hash is just a quick check to be able to partition objects into buckets such that objects in different buckets are definitely not equal.
First decide what makes two instances of the class equal or unequal, and implement equals accordingly. Next, look at the fields used in the equals method, and base the hashCode implementation on them, ensuring that if the instances are equal they have the same hashCode.
Patricia
Alexander - 20 Jul 2006 14:57 GMT > By "the hashCode() values" do you mean the fields that are used to > calculate the hash code, or the results it returns? I meant to say that the class should not base its equals() result only on comparing instances, but needs to take into account also the other fields which make two different instances "equal". In this case instances are not only equal if the passed object refers to the processed one, but also when the "name" is the same.
> If you just mean that equals and hashCode should be based on the same > set of fields, I agree Exactly
Alexander
Thomas Fritsch - 19 Jul 2006 15:04 GMT andrew.tanenbaum@katamail.com schrieb:
> Thomas Fritsch ha escrito: > [quoted text clipped - 8 lines] > problem, in any case now I have all the necessary knolwedge about how > hashmaps work For me it worked. The program below printed out "value = 1" as expected.
//---------------------------------------- import java.util.HashMap;
public class MyClass { public static void main(String[] args) { HashMap<MyClass,Integer> myHashMap = new HashMap<MyClass,Integer>(); MyClass obj1 = new MyClass("MyName"); myHashMap.put(obj1, 1);
MyClass obj2 = new MyClass("MyName"); Integer value = myHashMap.get(obj2); System.out.println("value = " + value); }
private final String name;
public MyClass(String s) { name = s; }
public String getName() { return name; }
public boolean equals(Object o) { if(o instanceof MyClass) return name.equals(((MyClass)o).getName()); else return super.equals(o); }
public int hashCode() { return name.hashCode(); } } //---------------------------------------------
 Signature Thomas
andrew.tanenbaum@katamail.com - 19 Jul 2006 14:39 GMT Thomas Fritsch ha escrito:
> Please make sure that MyClass has a hashCode() method consistent with > your equals() method. Something simple like this will probably work: > public int hashCode() { > return name.hashCode(); > } It doesn't work :-( For example, if I do
MyClass obj1 = new MyClass("Name"); MyClass obj2 = new MyClass("Name"); int hc1 = obj1.hashCode() int hc2 = obj2.hashCode()
hc1 and hc2 are two different value, even if the String is the same.
Matt Humphrey - 19 Jul 2006 14:56 GMT > Thomas Fritsch ha escrito: > [quoted text clipped - 12 lines] > > hc1 and hc2 are two different value, even if the String is the same. You must have left something out. Show the exact code you're using in MyClass.
andrew.tanenbaum@katamail.com - 19 Jul 2006 15:01 GMT Matt Humphrey ha escrito:
> You must have left something out. Show the exact code you're using in > MyClass. I got it, it was my fault with imported jars, now it works :-) Thanks to everybody, now I know how a fu**ing hashmap works
Patricia Shanahan - 19 Jul 2006 18:41 GMT > Thomas Fritsch ha escrito: > [quoted text clipped - 12 lines] > > hc1 and hc2 are two different value, even if the String is the same. In that case, I think the problem can be safely considered to be localized to the MyClass implementation, probably in either its constructor or its hashCode.
You could write a very simple test program, incorporating enough of the MyClass implementation to demonstrate the different hashCode results, and post it.
Here's an example, but it does not reproduce the problem:
public class HashTest { private String name;
public HashTest(String name) { this.name = name; }
public int hashCode() { return name.hashCode(); }
public static void main(String[] args) { HashTest obj1 = new HashTest("Name"); HashTest obj2 = new HashTest("Name"); int hc1 = obj1.hashCode(); int hc2 = obj2.hashCode(); System.out.printf("hc1=%d hc2=%d\n", hc1, hc2); } }
Patricia
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|