Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / July 2006

Tip: Looking for answers? Try searching our database.

How HashMap performs a get?

Thread view: 
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 Magazines

Get 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 ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.