TreeMap works but HashMap will not - is there a problem with my hashCode?

In the example below, I store objects in an array, a TreeMap and a HashMap in parallel. The array and TreeMap work as expected, but the HashMap behaves as if it there was no overloaded hashCode function. In this simple example, it should be an easy function to write, but for some reason it won't work ...

import java.util.*;

class MapTest{

privateclass WrappedIntegerimplements Comparable{

WrappedInteger (int _id){

id = _id;

}

publicint hashCode (){

return id;

}

publicboolean equals (WrappedInteger obj){

return obj.id == id;

}

public String toString (){

return String.format ("id %d", id);

}

publicint compareTo (Object o){

returnnew Integer (id).compareTo (((WrappedInteger) o).id);

}

privateint id;

}

privateclass BooleanArray{

BooleanArray (int maxLinear){

rg =newboolean [maxLinear];

treeMapTracker =new TreeMap<WrappedInteger, Boolean> ();

hashMapTracker =new HashMap<WrappedInteger, Boolean> ();

}

void put (WrappedInteger s,boolean f){

rg [s.hashCode ()] = f;

Boolean bTree = treeMapTracker.get (s);

Boolean bHash = hashMapTracker.get (s);

if (bHash ==null && bTree !=null){

System.out.println ("MAP TRACKER ERROR: already in TreeMap but not in HashMap: " + s.toString ());

}

if (bHash !=null && bTree ==null){

System.out.println ("MAP TRACKER ERROR: already in HashMap but not in TreeMap: " + s.toString ());

}

if (bTree ==null){

nPut++;

}

treeMapTracker.put (s, f);

hashMapTracker.put (s, f);

}

int size (){

if (nPut != treeMapTracker.size ()){

System.out.println ("MAP TRACKER ERROR: nPut=" + nPut +", treeMapTracker.size ()=" + treeMapTracker.size ());

}

if (nPut != hashMapTracker.size ()){

System.out.println ("MAP TRACKER ERROR: nPut=" + nPut +", hashMapTracker.size ()=" + hashMapTracker.size ());

}

return nPut;

}

Boolean get (WrappedInteger s){

Boolean bTree = treeMapTracker.get (s);

if (bTree ==null){

System.out.println ("MAP TRACKER ERROR: treeMapTracker.get (s)=null");

}elseif (rg [s.hashCode ()] != bTree){

System.out.println ("MAP TRACKER ERROR: rg [s.hashCode ()]=" + rg [s.hashCode ()] +", treeMapTracker.get (s)=" + bTree);

}

Boolean bHash = hashMapTracker.get (s);

if (bHash ==null){

System.out.println ("MAP TRACKER ERROR: hashMapTracker.get (s)=null");

}elseif (rg [s.hashCode ()] != bHash){

System.out.println ("MAP TRACKER ERROR: rg [s.hashCode ()]=" + rg [s.hashCode ()] +", hashMapTracker.get (s)=" + bHash);

}

returnnew Boolean (rg [s.hashCode ()]);

}

privateboolean rg [];

private Map<WrappedInteger, Boolean> treeMapTracker;

private Map<WrappedInteger, Boolean> hashMapTracker;

privateint nPut= 0;

}

publicvoid test (){

BooleanArray booleanArray =new BooleanArray (10);

booleanArray.put (new WrappedInteger (3),true);

booleanArray.put (new WrappedInteger (8),false);

booleanArray.put (new WrappedInteger (3),true);

booleanArray.put (new WrappedInteger (8),true);

booleanArray.put (new WrappedInteger (9),false);

System.out.println ("boolean array now has size: " + booleanArray.size ());

System.out.println ("[3] = " + booleanArray.get (new WrappedInteger (3)));

System.out.println ("[8] = " + booleanArray.get (new WrappedInteger (8)));

System.out.println ("[9] = " + booleanArray.get (new WrappedInteger (9)));

System.out.println ("[5] = " + booleanArray.get (new WrappedInteger (5)));

}

// This procedure exists for unit testing only and is never normally invoked.

publicstaticvoid main (String [] args){

MapTest governor =new MapTest ();

governor.test ();

}

}

Results:

MAP TRACKER ERROR: already in TreeMap but not in HashMap: id 3

MAP TRACKER ERROR: already in TreeMap but not in HashMap: id 8

MAP TRACKER ERROR: nPut=3, hashMapTracker.size ()=5

boolean array now has size: 3

MAP TRACKER ERROR: hashMapTracker.get (s)=null

[3] =true

MAP TRACKER ERROR: hashMapTracker.get (s)=null

[8] =true

MAP TRACKER ERROR: hashMapTracker.get (s)=null

[9] =false

MAP TRACKER ERROR: treeMapTracker.get (s)=null

MAP TRACKER ERROR: hashMapTracker.get (s)=null

[5] =false

[9235 byte] By [Crossrada] at [2007-10-2 9:22:47]
# 1
> public boolean equals (WrappedInteger obj)Wrong parameter type. You didn't properly override the equals method.
warnerjaa at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 2
Anyway, gee you're welcome.
warnerjaa at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 3

Yes, I remember getting zapped by that one too. You need to override thepublic boolean equals(Object o)

method. This methodpublic boolean equals (WrappedInteger obj)

doesn't do that.

DrClapa at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 4
Oops, sorry warnerja, my scroll finger got tired and I didn't see your post.
DrClapa at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 5

Another problem:

private class WrappedInteger implements Comparable {

should be

private class WrappedInteger implements Comparable<WrappedInteger> {

and then:

public int compareTo (WrappedInteger o) {

return new Integer (id).compareTo(o.id);

}

dubwaia at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 6

> Another problem:

> private class WrappedInteger implements Comparable {

> should be

> private class WrappedInteger implements

> Comparable<WrappedInteger> {

A noble effort, but it's probably in vain. The OP is apparantly among the many who don't know how to find their posts, so he'll never see your reply unless by pure luck. I have to come to that conclusion because it just can't be that he's just so rude as to never say a simple "thank you".

warnerjaa at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 7

> > Another problem:

> > private class WrappedInteger implements Comparable

> {

> > should be

> > private class WrappedInteger implements

> > Comparable<WrappedInteger> {

>

> A noble effort, but it's probably in vain. The OP is

> apparantly among the many who don't know how to find

> their posts, so he'll never see your reply unless by

> pure luck. I have to come to that conclusion because

> it just can't be that he's just so rude as to never

> say a simple "thank you".

Maybe. It's also possible the OP hasn't made it back to check for the

answer. In any event, if somone else stumbles across this, perhaps

they will get value from it.

dubwaia at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 8

> Maybe. It's also possible the OP hasn't made it back

> to check for the

> answer.

No I can't believe that, it's too sad. He/she posted the question almost a complete day ago, and I replied within about 10 minutes. It would be a reasonable assumption to believe if he/she was truly interested in a reply, that he/she would have checked (and responded with a simple "thank you") quite a while ago.

> In any event, if somone else stumbles across

> this, perhaps

> they will get value from it.

True.

warnerjaa at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 9
This has been very helpful to me.Thank you warnerjaThank you DrClalpThank you dubwaikind regardswalken
walken16a at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 10
You're just absoloooooootely welcome, walken.
warnerjaa at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 11
Many thanks for the quick reply - I made use of it quickly and I am sorry that I did not get back to you sooner to thank-you.
Crossrada at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 12

> Another problem:

> > private class WrappedInteger implements Comparable {

>

> should be

> > private class WrappedInteger implements

> Comparable<WrappedInteger> {

>

> and then:

> > public int compareTo (WrappedInteger o) {

> return new Integer (id).compareTo(o.id);

> }

>

Thanks for this - this problem is even more subtle, as the error does not result in either a compile error, a compile warning or the program failing.

Crossrada at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 13
Glad to see you got it working, and came back with the reply.
warnerjaa at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 14

If you're using java 1.5 and want to avoid this kind of nasty hard-to-spot semantic error you could get into the habit of using the Override annotation. For example

public class OverrideToy {

public OverrideToy() {}

@Override public boolean equals( OverrideToy t ) {

return false;

}

}

Will not compile.

I can't seem to get @Override and generics to co-exist though:

public class OverrideToy implements Comparable<OverrideToy> {

public OverrideToy() {}

@Override public int compareTo( OverrideToy o ) {

// TODO Auto-generated method stub

return 0;

}

}

complains too, even though it's really ok :(

sorabaina at 2007-7-16 23:29:43 > top of Java-index,Core,Core APIs...
# 15

> If you're using java 1.5 and want to avoid this kind

> of nasty hard-to-spot semantic error you could get

> into the habit of using the Override annotation. For

> example

>

> public class OverrideToy {

>public OverrideToy() {}

>

> @Override public boolean equals( OverrideToy t )

> t ) {

> return false;

>}

> }

>

> Will not compile.

>

> I can't seem to get @Override and generics to

> co-exist though:

>

> public class OverrideToy implements

> Comparable<OverrideToy> {

>public OverrideToy() {}

>

> @Override public int compareTo( OverrideToy o )

> o ) {

> // TODO Auto-generated method stub

> return 0;

>}

> }

>

>

> complains too, even though it's really ok :(

If you're going to do that, then rather than returning, you should include an assert false : "Implement this method!";

jverda at 2007-7-20 20:12:58 > top of Java-index,Core,Core APIs...