participate


Collections: Lists, Sets, and Maps - HashSet.contains()
<<   Back to Forum  |   Give us Feedback
This topic has 7 replies on 1 page.
mpacione
Posts:4
Registered: 9/14/99
HashSet.contains()   
Apr 26, 2005 5:04 AM

 
Hi,

I have a class hierarchy as follows: ModelElement is extended by Entity. Entity is extended by StateEntity and CompositeEntity. All three classes override Object.hashCode() and Object.equals(). I have an object of type HashSet<Entity> which contains CompositeEntity objects. I wish to determine if a particular CompositeEntity object is present in the HashSet, so I call HashSet.contains() with the CompositeEntity as argument. This returns false. However, iterating through the HashSet and comparing the values returned by hashCode() and equals() shows that there is an object contained in the set for which the hashCode matches that which is being searched for, and using equals() to compare them returns true. Given this, how is it possible that contains() returns false if HashSet uses hashCode() and equals() to determine object equality? Only one thread is operating on the HashSet.

Thanks,

Michael Pacione
 
Peter-Lawrey
Posts:6,487
Registered: 5/5/04
Re: HashSet.contains()   
Apr 26, 2005 5:35 AM (reply 1 of 7)  (In reply to original post )

 
For a proper test you need to compare hashCode() first as HashSet() does and then equals()
If two objects which are equal() but different hashCode()s will never get a match

e.g.
public class A {
private final int id;
private final String name;
 
public A (int id, String name) {
  this.id = id;
  this.name = name;
}
 
public int hashCode() {
   return id;
}
 
public boolean equals(Object obj) {
   if (obj instanceof A) {
    return name.equals(((A) obj).name);
   return false;
}
}
 
//
A a1 = new A(1, "one");
A a2 = new A(2, "one");
 
// a1.equals(a2) but a1.hashCode() != a1.hashCode();
 
ruthf104
Posts:97
Registered: 11/8/02
Re: HashSet.contains()   
Apr 26, 2005 5:44 AM (reply 2 of 7)  (In reply to original post )

 
I call HashSet.contains() with the
CompositeEntity as argument. This returns false.
However, iterating through the HashSet and comparing
the values returned by hashCode() and equals() shows
that there is an object contained in the set for
which the hashCode matches that which is being
searched for, and using equals() to compare them
returns true.

Is it possible that your equals method is not symmetric?

Let element be the element that you retrieve by iterating through the set. Let entity be the CompositeEntity instance that you passed as a parameter to contains().

You say that the equals method returns true for these two objects (and that they have the same hashCode). But does equals return true in both directions? ie

element.equals(entity)


and

entity.equals(element)


both return true?
 
Miro.Simko
Posts:2
Registered: 11/24/05
Re: HashSet.contains()   
Jul 20, 2006 8:53 AM (reply 3 of 7)  (In reply to #2 )

 
Hello,

I have exactly same problem and don' know how to solve it.
Any help is appreceated.

Regards,
Miro

here is the code, which simulates the problem:

package foo;
 
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
 
class Obj
{
  String s;
  
  public Obj()
  {
  }
 
  public Obj(String s)
  {
    this.s=s;
  }
  
  public boolean equals(Object obj)
  {
    Obj o=(Obj)obj;
    return s==null?o.s==null:s.equals(o.s);
  }
}
 
public class Foo
{
  public static void main(String[] args)
  {
    Set<Obj> set = new HashSet<Obj>();
    set.add(new Obj());
    
    Set<Obj> set2 = new HashSet<Obj>();
    
    for(Obj o : set)
      set2.add(new Obj(o.s));
    
    for(Obj o : set)
    {
      System.out.println(set2.contains(o));
 
      Iterator<Obj> iter = set2.iterator();
      while(iter.hasNext())
      {
        Obj e = iter.next(); 
        System.out.println(e.equals(o));
        System.out.println(o.equals(e));
      }
    }
  }
}
 
Merigold
Posts:14
Registered: 10/12/00
Re: HashSet.contains()   
Jul 20, 2006 11:08 AM (reply 4 of 7)  (In reply to original post )

 
To the original problem on this thread:

I would surmise that your CompositeEntity uses mutable attributes in its hash code calculation. You can't do that and expect a HashSet to store it properly. The hashCode must be immutable, and so must be the equals, to use HashSet; here's an example of how doing otherwise can cause a problem.

Step 1: define the CompositeEntity like this:

CompositeEntity has a public String variable called p. Its hash code is the hash code of p; its equality is if p's are equal.

CompositeEntity one = new CompositeEntity();
CompositeEntity two = new CompositeEntity();
one.p = "this";
HashSet test = new HashSet();
test.add(one);

The above code adds the entity one at the hash code value of "this"

two.p = "that";
one.p = "that";

(two.equals(one)) gives true
(two.hashCode() == one.hashCode()) gives true

test.contains(two) gives false

Because it's looking now at the hash code of "that" and one isn't there, it's at the hash code of "this" which was its hash code when it was added.

----

To the 3rd poster, with the code sample: you forgot to override hashCode() in your example, that's why it isn't working right. NOT the same problem as the OP.
 
jverd
Posts:51,815
Registered: 3/30/99
Re: HashSet.contains()   
Jul 20, 2006 8:27 PM (reply 5 of 7)  (In reply to #4 )

 
To the original problem on this thread:

Which was over a year ago. :-)



To the 3rd poster, with the code sample: you forgot
to override hashCode() in your example, that's why it
isn't working right. NOT the same problem as the OP.

Right. And here's a reasonable recipe for how:
http://developer.java.sun.com/developer/Books/effectivejava/Chapter3.pdf
 
jverd
Posts:51,815
Registered: 3/30/99
Re: HashSet.contains()   
Jul 20, 2006 8:28 PM (reply 6 of 7)  (In reply to #4 )

 
I would surmise that your CompositeEntity uses
mutable attributes in its hash code calculation. You
can't do that and expect a HashSet to store it
properly. The hashCode must be immutable,

Or you have to be able to detect when any of the hashcode-relevant fields changes, and then rehash or remove and re-add the entry.
 
Miro.Simko
Posts:2
Registered: 11/24/05
Re: HashSet.contains()   
Jul 21, 2006 12:18 AM (reply 7 of 7)  (In reply to #5 )

 
Thanks, that helps me. Till now I don't know about the need of overriding hashCode() method.
 
This topic has 7 replies on 1 page.
Back to Forum
 
Read the Developer Forums Code of Conduct

Click to email this message Email this Topic

Edit this Topic
  
 
 
Forums Statistics
    Users Online : 25
  • Guests : 129

About Sun forums
  • Sun Forums is a large collection of user generated discussions. It is here to help you ask questions, find answers, and participate in discussions.

    Check out our guide on Getting started with Sun Forums for a full walkthrough of how to best leverage the benefits of this community.

Powered by Jive Forums