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 2007

Tip: Looking for answers? Try searching our database.

HashTable

Thread view: 
George - 17 Jul 2007 13:33 GMT
Dear All,

I am using a HashTable with HashSets as the keys (they point to integers
and it has to be that way round because of an algorithm I am
implementing).

I calculate the HashSet from a different method and then I use
hashtablename.containsKey(hashset). The problem is that altough the values
of the hashset are identical containsKey will fail.

Any ideas as to how I might get the correct results?

George
Gordon Beaton - 17 Jul 2007 13:42 GMT
> I am using a HashTable with HashSets as the keys (they point to
> integers and it has to be that way round because of an algorithm I
[quoted text clipped - 5 lines]
>
> Any ideas as to how I might get the correct results?

Have you modified the HashSet in any way (added or removed elements)
after storing it in the HashTable?

Have you confirmed that the HashSet in the HashTable and the object
you use to find it with, in fact have the same hashCode()? Are they
equals()?

What kind of objects are stored in the HashSet, and did you remember
to implement hashCode() and equals() methods properly in *those*
objects?

/gordon

--
George - 17 Jul 2007 13:49 GMT
On Tue, 17 Jul 2007 Lekeas GK wrote...

|From: Gordon Beaton <n.o.t@for.email>
|Date: 17 Jul 2007 12:42:37 GMT
[quoted text clipped - 12 lines]
|Have you modified the HashSet in any way (added or removed elements)
|after storing it in the HashTable?
No, they have not been modified at all.

|Have you confirmed that the HashSet in the HashTable and the object
|you use to find it with, in fact have the same hashCode()? Are they
|equals()?

They contain two objects each, which are exactly the same. Does that not
make equal?

|What kind of objects are stored in the HashSet, and did you remember
|to implement hashCode() and equals() methods properly in *those*
|objects?

HashSet stores SigElement objects (custom datatype but simple - a couple
of string objects really). But would they not get these methods from the
Object class?

|/gordon
|
|--
Lew - 17 Jul 2007 13:54 GMT
Gordon Beaton:
> |Have you confirmed that the HashSet in the HashTable and the object
> |you use to find it with, in fact have the same hashCode()? Are they
> |equals()?

> They contain two objects each, which are exactly the same. Does that not
> make equal?

Yes, that does /not/ make the HashSets equal.

What is the definition of HashSet.equals()?

Signature

Lew

Gordon Beaton - 17 Jul 2007 14:12 GMT
> HashSet stores SigElement objects (custom datatype but simple - a
> couple of string objects really). But would they not get these
> methods from the Object class?

They do unless you've overridden the methods, which you should always
do when you store your own object types in any collection that uses
hashCode() and equals() on its contents. The default methods don't
work in most realistic situations.

Here's a test: create two distinct SigElements objects with the same
contents. Display their hashcodes and the results of s1.equals(s2). Do
they appear to be equivalent?

/gordon

--
Lew - 17 Jul 2007 13:53 GMT
George wrote:
>> I am using a HashTable with HashSets as the keys (they point to
>> integers and it has to be that way round because of an algorithm I
[quoted text clipped - 5 lines]
>>
>> Any ideas as to how I might get the correct results?

> Have you modified the HashSet in any way (added or removed elements)
> after storing it in the HashTable?
>
> Have you confirmed that the HashSet in the HashTable and the object
> you use to find it with, in fact have the same hashCode()?

Assuming java.util.HashSet, the hashCode() calculation is completely reliable.

> Are they equals()?

Ay, there's the rub.  They aren't.

> What kind of objects are stored in the HashSet, and did you remember
> to implement hashCode() and equals() methods properly in *those*
> objects?

Irrelevant.  He's comparing HashSets, not their contents.

It's hard to be sure without an SSCCE, but a couple of things might be wrong:

First of all, who provides the HashTable class?  Maybe there is something
strange about it.  (Unless you meant java.utilHashtable, but your spelling
says otherwise.  If you did mean Hashtable, why are you using that Map
implementation?  Is synchronization needed?)

Second, what is the definition of HashSet.equals()?  As it happens, you're
guaranteeing that the HashSet in the HashTable (sic) is different from the one
you're querying.  That's why the lookup is failing.

Signature

Lew

Gordon Beaton - 17 Jul 2007 14:01 GMT
> Irrelevant.  He's comparing HashSets, not their contents.

The hashcode of the HashSet is based on the hashcodes of the elements
it contains. A second HashSet containing supposedly identical objects,
but whose hashcodes are different, will itself have a different
HashCode. How can Hashtable.containsKey() succeed?

/gordon

--
Lew - 17 Jul 2007 14:03 GMT
>> Irrelevant.  He's comparing HashSets, not their contents.
>
> The hashcode of the HashSet is based on the hashcodes of the elements
> it contains. A second HashSet containing supposedly identical objects,
> but whose hashcodes are different, will itself have a different
> HashCode. How can Hashtable.containsKey() succeed?

You're absolutely right.

Signature

Lew

Gordon Beaton - 17 Jul 2007 14:05 GMT
>> Have you confirmed that the HashSet in the HashTable and the object
>> you use to find it with, in fact have the same hashCode()?
>
> Assuming java.util.HashSet, the hashCode() calculation is completely reliable.

What makes you think I implied that it wasn't?

/gordon

--
Lew - 17 Jul 2007 14:08 GMT
>>> Have you confirmed that the HashSet in the HashTable and the object
>>> you use to find it with, in fact have the same hashCode()?
>> Assuming java.util.HashSet, the hashCode() calculation is completely reliable.
>
> What makes you think I implied that it wasn't?

Bad thinking on my part.  Sorry.

Signature

Lew

George - 17 Jul 2007 14:16 GMT
I am refering to the classes available from java.util, you are right. But
if you construct a hashset containing objects o1 and o2 (assume any type
of objects) and a second hashset containing their clones, would the
hashcodes of the objects (and hence the hashcode of the hashset containing
them) be the same?

It would seem logical to me that the answer to this question should be
positive, but the results of my code suggest otherwise...:(

By overiding equals and hashCode, I get something more closer to the
result I want but a bit further from what I would assume as correct
behaviour. If you could provide any explanation as to why the answer to my
assumption above shoulbe no, I would be grateful.

Thanks,
George

On Tue, 17 Jul 2007 Lekeas GK wrote...

|From: Lew <lew@lewscanon.nospam>
|Date: Tue, 17 Jul 2007 09:08:32 -0400
[quoted text clipped - 10 lines]
|--
|Lew
Chris Dollin - 17 Jul 2007 14:26 GMT
> I am refering to the classes available from java.util, you are right. But
> if you construct a hashset containing objects o1 and o2 (assume any type
> of objects) and a second hashset containing their clones, would the
> hashcodes of the objects (and hence the hashcode of the hashset containing
> them) be the same?

No. (Well, it /could/ be. By coincidence. But likely not.)

> It would seem logical to me that the answer to this question should be
> positive, but the results of my code suggest otherwise...:(

The default hashcode is a magic number (something like the original
address of the object, or maybe an allocation count, or something).
It's nothing to do with any members you may have in the object. Also
the default .equals is ==.

Signature

Hewlett-Packard Limited                                          registered no:
registered office: Cain Road, Bracknell, Berks RG12 1HN          690597 England

Lew - 17 Jul 2007 14:34 GMT
>> I am refering to the classes available from java.util, you are right. But
>> if you construct a hashset containing objects o1 and o2 (assume any type
[quoted text clipped - 3 lines]
>
> No. (Well, it /could/ be. By coincidence. But likely not.)

Even if the hash codes of the two HashSets (not "hashset") were the same, the
two would still not be equals() unless the objects were equals().

Similarly for any two objects.  Even if the hash codes are the same, they
don't necessarily equals() each other.

Signature

Lew

Lew - 17 Jul 2007 14:26 GMT
> I am refering to the classes available from java.util, you are right. But
> if you construct a hashset [sic] containing objects o1 and o2 (assume any type
> of objects) and a second hashset [sic] containing their clones, would the
> hashcodes [sic] of the objects (and hence the hashcode [sic] of the hashset [sic] containing
> them) be the same?

Only if the class of the objects in the set overrode equals() to indicate
value equality instead of the default reference equality.

So, for example, given a class that does not override equals():

public class Foo
{
  private String f;
  private String g;
  // public accessor and mutator methods ...
}

two distinct Foo objects f1 and f2 aren't equal even if f1.f.equals( f2.f )
and f1.g.equals( f2.g ).  f1 != f2 even if f1.f == f2.f and f1.g == f2.g.

Btw, it's "HashSet".

Signature

Lew

Lew - 17 Jul 2007 14:29 GMT
> f1 != f2 even if f1.f == f2.f and f1.g == f2.g.

I meant, "! f1.equals( f2 ) even if ...".
Hendrik Maryns - 17 Jul 2007 15:26 GMT
George schreef:
> I am refering to the classes available from java.util, you are right. But
> if you construct a hashset containing objects o1 and o2 (assume any type
> of objects) and a second hashset containing their clones, would the
> hashcodes of the objects (and hence the hashcode of the hashset containing
> them) be the same?

Ah, here’s the catch: clones are not == equal.  I.e. obj.clone() != obj.
But if you override equals (which you should), then
obj.clone().equals(obj) should be true.  (Make it true!)

> By overiding equals and hashCode, I get something more closer to the
> result I want but a bit further from what I would assume as correct
> behaviour. If you could provide any explanation as to why the answer to my
> assumption above shoulbe no, I would be grateful.

Then you are doing something wrong.  Read the link in my sig if you want
more help.

And did you consider Lew’s advice to use HashMap instead of Hashtable?

H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
Patricia Shanahan - 17 Jul 2007 21:18 GMT
> I am refering to the classes available from java.util, you are right. But
> if you construct a hashset containing objects o1 and o2 (assume any type
[quoted text clipped - 4 lines]
> It would seem logical to me that the answer to this question should be
> positive, but the results of my code suggest otherwise...:(

These paragraphs strongly imply that you consider clones to be equal.
That means two distinct instances of your class can be equal, so the
Object equals and hashCode behavior is completely wrong for that class.
You do need to override.

> By overiding equals and hashCode, I get something more closer to the
> result I want but a bit further from what I would assume as correct
> behaviour. If you could provide any explanation as to why the answer to my
> assumption above shoulbe no, I would be grateful.

"something more closer" suggests that you are not there yet. If so, I
suggest doing the following:

1. Write a trivial hashCode() that always returns zero.

2. Concentrate on equals. Think carefully about what determines whether
an instance of your class is equal to another object, and implement that
test as your equals method.

The hash-based collections work correctly, but inefficiently, with a
trivial hashCode().

Once you are sure equals is correct, go back and implement hashCode so
that all equal instances have the same hashCode while minimizing
collisions between unequal objects.

Patricia
George - 18 Jul 2007 14:56 GMT
That is not really the case in my program - I will briefly try to explain
the situation.

I have a custom data structure, say custom1, made up of two string fields
and another custom data type, say custom2. So, there is a series of
custom2 objects creation, then used for a series of custom1 object
creation. The custom1 class also has a static HashTable field, indexed by
a HashSet. The HashSet is constructed in a separate method which has
statements of the type hashsetname.add(new custom3(...)).

When this method finishes, before insertion into the main HashTable I run
a check with containsKey - the problem is that it fails even for custom3
objects with exactly the same fields.

Please offer some advice if you can, as I am stuck at this point for about
a week now and it brought all my work to a halt.

Regards,
George

On Tue, 17 Jul 2007 Lekeas GK wrote...

|From: Patricia Shanahan <pats@acm.org>
|Date: Tue, 17 Jul 2007 13:18:19 -0700
[quoted text clipped - 36 lines]
|
|Patricia
Lew - 18 Jul 2007 15:13 GMT
> That is not really the case in my program - I will briefly try to explain
> the situation.

Please do not top-post - it makes it harder to understand to what you are
responding.

/What/ is really not the case?  That you need to override equals()?  But you
most certainly do need to.

> I have a custom data structure, say custom1, made up of two string fields
> and another custom data type, say custom2. So, there is a series of
> custom2 objects creation, then used for a series of custom1 object
> creation. The custom1 class also has a static HashTable field, indexed by

Again, it's "Hashtable", not "HashTable".

> a HashSet. The HashSet is constructed in a separate method which has
> statements of the type hashsetname.add(new custom3(...)).

Thus guaranteeing that the inserted objects do not == objects in another Set.

> When this method finishes, before insertion into the main HashTable I run
> a check with containsKey - the problem is that it fails even for custom3
> objects with exactly the same fields.

Because you did not override equals(), as has been repeatedly explained.

> Please offer some advice if you can, as I am stuck at this point for about
> a week now and it brought all my work to a halt.

My advice is to follow the advice you've already been given.

From: Patricia Shanahan <pats@acm.org>
> |These paragraphs strongly imply that you consider clones to be equal.
> |That means two distinct instances of your class can be equal, so the
> |Object equals and hashCode behavior is completely wrong for that class.
> |You do need to override.
...
> |"something more closer" suggests that you are not there yet. If so, I
> |suggest doing the following:
[quoted text clipped - 11 lines]
> |that all equal instances have the same hashCode while minimizing
> |collisions between unequal objects.

Signature

Lew

Patricia Shanahan - 18 Jul 2007 15:33 GMT
> That is not really the case in my program - I will briefly try to explain
> the situation.

I'm afraid I don't really understand this remark, because you also say
"even for custom3 objects with exactly the same fields" which also
strongly suggest that two distinct custom3 instances can be equal,
exactly the situation I was talking about.

> I have a custom data structure, say custom1, made up of two string fields
> and another custom data type, say custom2. So, there is a series of
[quoted text clipped - 9 lines]
> Please offer some advice if you can, as I am stuck at this point for about
> a week now and it brought all my work to a halt.
...

I'm afraid the only advice that will work is essentially the advice
everyone has been giving you.

You need to look VERY closely at the equals implementation for custom3.

First temporarily take hashCode out of the picture by implementing it in
each customN class as follows:

public int hashCode(){
  return 0;
}

That will make HashSet inefficient, but make it impossible for hashCode
bugs to prevent correct HashSet operation. When everything is working
functionally you should implement a good hashCode for each class,
matching its equals method.

You need to work through each of your classes, implementing AND TESTING
equals. Make sure you test equals with parameter type Object, not
custom3 etc.

I would begin with custom2, because it seems to be bottom of the
dependency hierarchy. Can two custom2 objects be equal because they have
equal fields, without being the same object? If so, write an equals
method that tests whether they have the same fields.

At each step, make sure you have a overridden hashCode with the trivial
version, and that you have tested equals and are happy with the results.

Once custom3's equals method returns true exactly when you think the two
objects are equal, your HashSet containsKey test will work just fine.

If this advice does not solve your problem, I suggest an SSCCE:
http://www.physci.org/codes/sscce/

Patricia
Patricia Shanahan - 18 Jul 2007 17:01 GMT
> I have a custom data structure, say custom1, made up of two string fields
> and another custom data type, say custom2. So, there is a series of
> custom2 objects creation, then used for a series of custom1 object
> creation. The custom1 class also has a static HashTable field, indexed by
> a HashSet. The HashSet is constructed in a separate method which has
> statements of the type hashsetname.add(new custom3(...)).

Here's a different approach to explaining what I think is going on. I've
written two trivial classes, NoEquals and HasEquals. Each has two String
fields. The difference is that NoEquals inherits equals and hashCode
from Object. HasEquals has a trivial, dummy hashCode and an equals that
treats HasEquals instances with equal fields as being equal.

I also wrote a test method that takes a pair of references and does some
tests of the sorts of things that I gather, from your messages, are
going on in your program, constructing a Set of instances of the class
and using it as a Map key. It is called three times, with a pair of
NoEquals objects, with an equal pair of HasEquals objects, and with an
unequal pair of HasEquals objects.

The test demonstrates how the results of the Set contains and Map
containsKey methods depend on the underlying equals implementation in my
classes. If this program does not explain what is going on in your
code, try to modify it to demonstrate the problem and post the result.

Output:

NoEquals objects
left == right is false
left.equals(right) is false
s1.contains(right) is false
m.containsKey(s1) is false

equal HasEquals objects
left == right is false
left.equals(right) is true
s1.contains(right) is true
m.containsKey(s1) is true

unequal HasEquals objects
left == right is false
left.equals(right) is false
s1.contains(right) is false
m.containsKey(s1) is false

Source code - copy to an EqualsDemo.java file:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class EqualsDemo {

  static void test(Object left, Object right) {
    System.out.printf("left == right is %b%n", left == right);
    System.out.printf("left.equals(right) is %b%n", left
        .equals(right));
    Set<Object> s1 = new HashSet<Object>();
    s1.add(left);
    System.out.printf("s1.contains(right) is %b%n", s1
        .contains(right));
    Map<Object, String> m = new HashMap<Object, String>();
    m.put(s1, "Dummy string");
    Set<Object> s2 = new HashSet<Object>();
    s2.add(right);
    System.out.printf("m.containsKey(s1) is %b%n", m
        .containsKey(s2));
  }

  public static void main(String[] args) {
    System.out.println("NoEquals objects");
    test(new NoEquals("a", "b"), new NoEquals("a", "b"));
    System.out.println();
    System.out.println("equal HasEquals objects");
    test(new HasEquals("a", "b"), new HasEquals("a", "b"));
    System.out.println();
    System.out.println("unequal HasEquals objects");
    test(new HasEquals("a", "b"), new HasEquals("a", "B"));
  }
}

class NoEquals {
  String field1;
  String field2;
  NoEquals(String field1, String field2) {
    this.field1 = field1;
    this.field2 = field2;
  }
}

class HasEquals {
  String field1;
  String field2;
  HasEquals(String field1, String field2) {
    this.field1 = field1;
    this.field2 = field2;
  }
  public boolean equals(Object obj) {
    if (obj == null || !(obj instanceof HasEquals)) {
      return false;
    } else {
      HasEquals other = (HasEquals) obj;
      return field1.equals(other.field1)
          && field2.equals(other.field2);
    }
  }

  /*
   * Dummy hashCode for testing equals, do not use in production
   * code.
   */
  public int hashCode() {
    return 0;
  }
}
Piotr Kobzda - 19 Jul 2007 08:59 GMT
[...]

Just a small comment to your nice demo:

>     if (obj == null || !(obj instanceof HasEquals)) {

Since null is never an instance of any class, enough is to say:

      if (!(obj instanceof HasEquals)) {

piotr
Twisted - 19 Jul 2007 19:57 GMT
> [...]
>
[quoted text clipped - 5 lines]
>
>        if (!(obj instanceof HasEquals)) {

Does this definitely work? Any language lawyers around? I can see
three sensible possibilities:

null instanceof HasEquals == true (since HasEquals foo = null; is
legal)
null instanceof HasEquals == false (since no constructed HasEquals
instance is null)
null instanceof HasEquals throws NullPointerException (since the
reference is null)

and I don't see that it's in any way "obvious" which of the three the
Java folks would have chosen. All make their own kind of sense.
Patricia Shanahan - 19 Jul 2007 20:13 GMT
>>[...]
>>
[quoted text clipped - 18 lines]
> and I don't see that it's in any way "obvious" which of the three the
> Java folks would have chosen. All make their own kind of sense.

Fortunately, the JLS resolves the issue: "At run time, the result of the
instanceof operator is true if the value of the RelationalExpression is
not null and the reference could be cast (§15.16) to the ReferenceType
without raising a ClassCastException. Otherwise the result is false."

http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.20.2

Piotr is indeed right, and the expression could be simplified. However,
I will probably still go on coding the explicit null check in cases in
which it is not necessary, because I think it makes the correctness of
the code more obvious.

Patricia
Lasse Reichstein Nielsen - 19 Jul 2007 20:40 GMT
>>        if (!(obj instanceof HasEquals)) {
>
> Does this definitely work?

Yes

> Any language lawyers around? I can see three sensible possibilities:
>
> null instanceof HasEquals == true (since HasEquals foo = null; is
> legal)

Nope. JLS 3 section 15.20.2:
 "At run time, the result of the instanceof operator is true if the
  value of the RelationalExpression is not null and the reference
  could be cast (§15.16) to the ReferenceType without raising a
  ClassCastException. Otherwise the result is false."
<URL:http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.20.2>

> null instanceof HasEquals == false (since no constructed HasEquals
> instance is null)

It's false, just because that's what the specification of "instanceof"
says. But this would be a good argument for that decission. It's
quite simple to say whether the null reference points to an instance
of a specific class. It doesn't.

> and I don't see that it's in any way "obvious" which of the three the
> Java folks would have chosen. All make their own kind of sense.

Indeed. I was guessing the first one myself at one point (assignment
is legal, so instanceof must agree), which caused me to learn the
real answer the hard way - it's the best way to learn if you want
to remember the answer :)

/L
Signature

Lasse Reichstein Nielsen  -  lrn@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
 'Faith without judgement merely degrades the spirit divine.'

Twisted - 21 Jul 2007 11:04 GMT
> Indeed. I was guessing the first one myself at one point (assignment
> is legal, so instanceof must agree), which caused me to learn the
> real answer the hard way - it's the best way to learn if you want
> to remember the answer :)

IMO, Patricia is right and it's better to not rely on something
unobvious like that with multiple plausible interpretations. I will
continue to code explicit null checks as well. The compiler should be
able to optimize them out if you two are correct about the
specification, so it shouldn't be a performance hit or anything like
that.
rossum - 17 Jul 2007 16:00 GMT
>Dear All,
>
[quoted text clipped - 9 lines]
>
>George
Have a look at Item 8: "Always override hashCode when you override
equals" in Chapter 3 of "Effective Java":
http://developer.java.sun.com/developer/Books/effectivejava/Chapter3.pdf

rossum


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



©2009 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.