implementing hashcode and equals
Is there anything more than performance reasons to always implement hashCode when you implement equals? If I understand correctly, when you put items in a hashtable it chooses the bucket by the hashcode and checks there is no equal item with the equals method. So it should still work if you never implement the hashcode method. But is there any other reason to implement hashCode than performance? Or have I just understood this completely wrong?
[468 byte] By [
teka] at [2008-3-7]

> Is there anything more than performance reasons to
> always implement hashCode when you implement equals?
Yes. Read the API docs for equals and hashCode. In particular, notice that to obey the contracts, any two objects for which equals returns true, must have the same hashCode.
> If I understand correctly, when you put items in a
> hashtable it chooses the bucket by the hashcode and
> checks there is no equal item with the equals method.
If you use two equal keys in the hashtable, the second should overwrite the first. If they have different hashcodes, this will not happen.
> So it should still work if you never implement the
> hashcode method. But is there any other reason to
> implement hashCode than performance? Or have I just
> understood this completely wrong?
Consider the following code (I have implemented equals, but not implemented hashCode). Run it, then uncomment the hashCode method and run it again:
import java.util.HashSet;
import java.util.Set;
public final class MyObject {
private int i;
MyObject(int i) {
this.i = i;
}
public final boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof MyObject)) {
return false;
}
MyObject that = (MyObject)obj;
return this.i == that.i;
}
//public int hashCode() {
//return i;
//}
public static void main(String[] args) {
MyObject obj1 = new MyObject(1);
MyObject obj2 = new MyObject(1);
System.out.println("obj1.equals(obj2): "+obj1.equals(obj2));
System.out.println("obj1.hashCode(): "+obj1.hashCode());
System.out.println("obj2.hashCode(): "+obj2.hashCode());
Set set = new HashSet();
set.add(obj1);
System.out.println("set.size(): "+set.size());
System.out.println("set.contains(obj2): "+set.contains(obj2));
set.add(obj2);
System.out.println("set.size(): "+set.size());
}
}
Everything you say is true. And your example shows that point well. However, what if I just implement a hashCode that always returns 0? How will this work then? And does it have any differences than performance?
Here is an example
[code]
import junit.framework.*;
import java.util.*;
public class EqualsTest extends TestCase
{
public void testHashCode()
{
Map hashTable = new Hashtable();
hashTable.put( new TestItem( 0 ), "0" );
hashTable.put( new TestItem( 1 ), "1" );
assertEquals( 2, hashTable.size() );
Set hashSet = new HashSet();
hashSet.add( new TestItem( 0 ));
hashSet.add( new TestItem( 1 ) );
assertEquals( 2, hashSet.size() );
}
private class TestItem
{
private final int i;
public TestItem( int i )
{
this.i = i;
}
public boolean equals( Object o )
{
final TestItem testItem = ( TestItem ) o;
return i == testItem.i;
}
public int hashCode()
{
return 0;
}
}
}
[/code}