Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 Java TYS
Index -> Programming, Java -> Java Help
View previous topic Printable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
Hikaru79




PostPosted: Mon Jan 21, 2008 9:58 pm   Post subject: Java TYS

I noticed that a lot of other, fairly obscure, languages have TYS' (Io, anyone?), but Java doesn't; since it's a popular language, and I love TYS', here I go Smile

I'll get things started.
Java:
import java.util.*;

class Foo {
        private String name;

        public Foo(String name) {
                this.name = name;
        }

        public String getName() {
                return name;
        }

        public boolean equals(Foo otherFoo) {
                return this.getName().equals(otherFoo.getName());
        }

        public int hashCode() {
                return name.hashCode();
        }
}

public class Test {

        public static void main(String [] args) {
                HashMap<Foo, String> test = new HashMap<Foo, String>();
                Foo firstFoo = new Foo("foo");
                test.put(firstFoo, firstFoo.getName());
                Foo secondFoo = new Foo("foo");
                System.out.println("Equals:   " + firstFoo.equals(secondFoo));
                System.out.println("Contains: " + test.containsKey(secondFoo));
                System.out.println("Why is the first statement true, but the second false!?");
                System.out.println("I overloaded hashCode and equals, so it should work!");
                System.out.println("At least, according to http://java.sun.com/javase/6/docs/api/java/util/Map.html#containsKey(java.lang.Object) it should!");
                System.out.println("So where's the problem?");
                System.exit(-1);
        }

}

The problem is explained in the println's at the end there. What is causing the "strange" behaviour, and how would you fix it so that it works as reasonably expected?

I encountered this "bug" in some of my own code; actually in my code, it was a ConcurrentHashMap in a (very) multithreaded program, so for a very long time I assumed it was a concurrency problem, and tried to find problems with my synchronization.

When that didn't work, I decided to see if the problem could be reproduced in a single thread. Oh, there it is. Oops Embarassed.
The actual problem has nothing to do with threads; it's much simpler than that.

Enjoy Very Happy
Sponsor
Sponsor
Sponsor
sponsor
HeavenAgain




PostPosted: Mon Jan 21, 2008 10:09 pm   Post subject: RE:Java TYS

first one is true, because you are simply comparing the string, which they are equal, and now the 2nd one is a bit tricky... you are saying if the map contains the "reference" to secondFoo, not the String itself... and so it doesnt
if you try Foo secondFoo = firstFoo; then i think this will work...
tricky part is the String and reference instead of the actual "value" or at least i think Razz
HellblazerX




PostPosted: Mon Jan 21, 2008 10:21 pm   Post subject: RE:Java TYS

That, or you could make your Foo class Comparable, and make your own compareTo () method that the HashMap will use.
Hikaru79




PostPosted: Mon Jan 21, 2008 10:23 pm   Post subject: Re: RE:Java TYS

HeavenAgain @ Mon Jan 21, 2008 11:09 pm wrote:
first one is true, because you are simply comparing the string, which they are equal, and now the 2nd one is a bit tricky... you are saying if the map contains the "reference" to secondFoo, not the String itself... and so it doesnt
if you try Foo secondFoo = firstFoo; then i think this will work...
tricky part is the String and reference instead of the actual "value" or at least i think Razz


Well, yes, it's no mystery why equals() returns true; but if you read the API docs, apparently containsKey() simply uses equals() to decide if the key exists -- so if WE get a true from equals(), why doesn't the HashMap?
Doing secondFoo = firstFoo doesn't work either Smile You're not quite on the right track...

HellblazerX wrote:
That, or you could make your Foo class Comparable, and make your own compareTo () method that the HashMap will use.

Try it and see Wink I think you'll find that doesn't work. HashMap doesn't need something to be Comparable, it just needs equals()/hashCode().
HeavenAgain




PostPosted: Mon Jan 21, 2008 10:29 pm   Post subject: RE:Java TYS

well, yeah i just tried using Foo secondFoo = firstFoo; and both give me true... Rolling Eyes
and you are having 2 reference types here, one is the address to the Foo object, and after that it is another address to the String name.... by using equals you are only comparing the first reference, which is the Foo and Foo class, obviously they are not equal Shocked or am i not making any sense here...
HellblazerX




PostPosted: Mon Jan 21, 2008 10:33 pm   Post subject: RE:Java TYS

Does it have anything to do with your hashCode () method? It's possible the two hashcodes for your String aren't the same.
Hikaru79




PostPosted: Mon Jan 21, 2008 10:40 pm   Post subject: Re: RE:Java TYS

HeavenAgain @ Mon Jan 21, 2008 11:29 pm wrote:
well, yeah i just tried using Foo secondFoo = firstFoo; and both give me true... Rolling Eyes

Hm, sorry, you're right; it would, but this is sort of sidestepping the problem. I'm defining my own equals() for the purpose of being able to equate different objects which have a name in common (of course in this case, Foo only HAS a name, but it could easily carry other data as well). Your solution will only work if the two references are literally pointing at the same thing.

HeavenAgain wrote:
and you are having 2 reference types here, one is the address to the Foo object, and after that it is another address to the String name.... by using equals you are only comparing the first reference, which is the Foo and Foo class, obviously they are not equal Shocked or am i not making any sense here...

I'm not sure what you mean here. Both firstFoo and secondFoo are Foo references. I can compare them for equality and even though they are two different references, they give me that they are equal (this is good). But when I put one into the HashMap, it fails to recognize firstFoo as being equal (in the sense I defined it) to secondFoo. Why?

Hint: It doesn't really have anything to do with references. It has more to do with method overloading and polymorphism. This is a big hint Razz

HellBlazerX wrote:
Does it have anything to do with your hashCode () method? It's possible the two hashcodes for your String aren't the same.

Nope, equal Strings have equal hashCodes(), but you're getting closer Smile
HellblazerX




PostPosted: Mon Jan 21, 2008 10:48 pm   Post subject: RE:Java TYS

Equals () isn't properly overloaded because the parameter passed in isn't the same? O btw, I don't Java rite now so i can't test these out.
Sponsor
Sponsor
Sponsor
sponsor
Hikaru79




PostPosted: Mon Jan 21, 2008 10:52 pm   Post subject: Re: RE:Java TYS

HellblazerX @ Mon Jan 21, 2008 11:48 pm wrote:
Equals () isn't properly overloaded because the parameter passed in isn't the same? O btw, I don't Java rite now so i can't these out.


Bingo Very Happy In what sense is it not 'passed in the same'? How would you modify this so it works?

But your answer is correct! (though vague, for now)
HellblazerX




PostPosted: Mon Jan 21, 2008 10:57 pm   Post subject: Re: Java TYS

Have the parameter for .equals () set as an Object, and then typecast the parameter when checking for equality:
code:

public boolean equals (Object otherFoo) {
     return this.getName ().equals (((Foo)otherFoo).getName ());
}

I'm guessing HashMap will automatically typecast everything into Object before using the .equals () method.
Hikaru79




PostPosted: Mon Jan 21, 2008 11:00 pm   Post subject: Re: Java TYS

HellblazerX @ Mon Jan 21, 2008 11:57 pm wrote:
Have the parameter for .equals () set as an Object, and then typecast the parameter when checking for equality:
code:

public boolean equals (Object otherFoo) {
     return this.getName ().equals (((Foo)otherFoo).getName ());
}

I'm guessing HashMap will automatically typecast everything into Object before using the .equals () method.


Excellent, except that your code would crash any time you tried to compare a Foo object to a non-Foo object (instead of just returning false). I'll just add the last piece:
Java:
return ((otherFoo instanceof Foo) && this.getName().equals (((Foo)otherFoo).getName()));


+50 bits for you Wink
Aziz




PostPosted: Sat Feb 23, 2008 1:38 pm   Post subject: RE:Java TYS

Wow, such a little thing to over look, eh? That's why the @Override annotation was created!
Display posts from previous:   
   Index -> Programming, Java -> Java Help
View previous topic Tell A FriendPrintable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 1  [ 12 Posts ]
Jump to:   


Style:  
Search: