Java HashSet Problem

R

Roedy Green

I didn't expect you to agree with me; your reputation precedes you.
Suffice to say though, your own opinion regarding readability and clarity
is not the last word on the matter.

The general rule is brevity adds to clarity. Adding code that does not
do anything is just one more thing you have to needlessly figure out.

Agreed that a regular pattern makes it easy to extend, but that code
had needless fillips that disguised the regularity.
 
R

Roedy Green

Indeed. Perhaps if you actually *read* the thread before posting your
reply, you would have seen that the correct answer had already been
posted twice by others.

Guilty as charged. In general I don't read all the threads, mainly
because so few of the posts have anything to do with the topic at
hand. Most are about one-up-manship games, as was your post.
 
T

twizansk

Guilty as charged. In general I don't read all the threads, mainly
because so few of the posts have anything to do with the topic at
hand. Most are about one-up-manship games, as was your post.


Thanks everyone. I overrode equals() instead of overloading it and
now it works perfectly. Stupid mistake o my part but I guess you
learn something new every day.
 
A

Andrew Thompson

On Mar 15, 5:02 am, (e-mail address removed) wrote:
..
...I overrode equals() instead of overloading it and
now it works perfectly.   Stupid mistake o my part but I guess you
learn something new every day.

That's part of what what makes them (days) fun. :)
 
P

pjvleeuwen

Let's digg up this thread because to me it seems the JavaDoc on
HashSet#contains(Object o) is not right.

It all started with these lines in a unit-test (and a failure on the
last line):
Person bob = new Person("Bob", 'm', new Date(1, 7, 2007), "1");
Set<Person> store = new HashSet<Person>();
store.add(bob);
assertTrue(bob.equals(new Person( //
"Bob", 'm', new Date(1, 7, 2007), "1")));
assertTrue(store.contains(bob));
assertTrue(store.contains(new Person( //
"Bob", 'm', new Date(1, 7, 2007), "1")));

Person overwrites equals(Object) in a correct way, but does not
overwrite the hashCode() method.
When I look at the JavaDoc of HashSet#contains(Object o) I get:
"
Returns true if this set contains the specified element. More
formally,
returns true if and only if this set contains an element e such
that
(o==null ? e==null : o.equals(e)).
"

But! when we check the source of the HashSet#contains(Object
ourPerson) we see it uses HashMap.containsKey(Object ourPerson) which
uses HashMap.getEntry(Object ourPerson). now getEntry's source looks
like:
"
int hash = (key == null) ? 0 : hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
"

If I am reading this correctly, then the equals method is only
evaluated when the hashes of the two objects are equals. Since I did
not overwrite Object#hashCode() HashSet#contains(Object) returns false
in the above scenario.

Since I couldn't find any other post on this matter (or bug-report) I
want to ask you guys to check my above statements.

Ow, for the record the HashSet class I have is labeled:
/*
* @(#)HashSet.java 1.37 06/04/21
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
and my java lives In C:\jdk1.6.0_03 (so that would probably be the
version then)

Cheers,
Paul
 
P

Patricia Shanahan

Person overwrites equals(Object) in a correct way, but does not
overwrite the hashCode() method.

Almost invariably, equals cannot be overridden "in a correct way"
without also overriding hashCode().

....
If I am reading this correctly, then the equals method is only
evaluated when the hashes of the two objects are equals. Since I did
not overwrite Object#hashCode() HashSet#contains(Object) returns false
in the above scenario.
....

Correct, but to turn this into a problem in HashSet, rather than in yoru
class, you need to ignore a critical piece of documentation.

HashSet, like all Java classes, is limited to operating on objects whose
class extends, directly or indirectly, java.lang.Object. Therefore, its
implementation can assume that the objects in the set follow the rules
stated in the java.lang.Object documentation.

From the documentation for equals: "Note that it is generally necessary
to override the hashCode method whenever this method is overridden, so
as to maintain the general contract for the hashCode method, which
states that equal objects must have equal hash codes.". This makes
overriding equals without maintaining the hashCode contract incorrect.

From the documentation for hashCode: "If two objects are equal according
to the equals(Object) method, then calling the hashCode method on each
of the two objects must produce the same integer result."

The Java APIs are full of method implementations that depend on methods
in other classes behaving according to some aspect of the documented
contract for one of the class's superclasses or interfaces. Generally,
those dependencies are only documented through the type of the
reference. Otherwise, the documentation would be impossibly cluttered
with some phrase like "... provided parameter x of type X conforms to
the X contract."

Requiring an Object reference means that the Object contract applies,
not that there is no contract.

Patricia
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top