From: Lew on 14 Jun 2010 14:38 Lew wrote: >>> This method will appear to work if passed a 'Foo' argument because the >>> 'Foo' argument matches more specifically than the 'Object' argument to >>> the other 'equals()' method in the class, but it will fail in general >>> when clients pass an 'Object' argument and bypass the specific overload, >>> getting the parent-class version instead. > Simon Brooke wrote: >> Sorry, why is this a mistake? If a 'Bar' argument is passed, equals must >> return false anyway. Does it matter which implementation of equals is >> invoked? > Eric Sosman <esos...(a)ieee-dot-org.invalid> wrote: > The second sentence is often true, even "usually" true, but > not universally true. It sometimes makes sense for the equals() > of one class to return true when handed an instance of a different > class. For example, consider the equals() contract of Set: > If 'equals(Object)' is not overridden, then it likely returns 'false' even for an argument where 'equals(Foo)' would return 'true' if it were invoked on the '(Foo)' cast of that instance. Programs usually invoke 'equals(Object)', not 'equals(Foo)', so you get results you don't expect. -- Lew
From: ilan on 14 Jun 2010 14:46 Lew <lew(a)lewscanon.com> writes: > Lew wrote: >>> Your method overload question is quite important, actually. It's a >>> common mistake to overload 'equals()' when the intent is to override, >>> e.g., >>> >>> public class Foo >>> { >>> ... >>> public boolean equals( Foo other ) >>> { >>> ... >>> } >>> } >>> >>> This method will appear to work if passed a 'Foo' argument because the >>> 'Foo' argument matches more specifically than the 'Object' argument to >>> the other 'equals()' method in the class, but it will fail in general >>> when clients pass an 'Object' argument and bypass the specific overload, >>> getting the parent-class version instead. >> > > Simon Brooke wrote: >> Sorry, why is this a mistake? If a 'Bar' argument is passed, equals must >> return false anyway. Does it matter which implementation of equals is >> invoked? >> > > Yes. As I already stated in my post, it will fail in the general case > when clients invoke it with an 'Object' argument. You will then get > the non-overridden 'equals(Object)' method from the parent class, > which typically provides object identity comparison rather than value > comparison, or else value comparison on the wrong fields. > >> I can see how this might matter for other methods with different >> semantics, but why equals, particularly? >> > > The parent 'equals()' method typically is one of those "other methods > with different semantics". The semantics of 'equals(Object)' will > differ from that of 'equals(Foo)' without special care, i.e., an > override of the former that invokes the latter. > > 'equals()' is typically called with an 'Object' argument, and > therefore the overload will not be invoked. Things like collections > depend on the method to have an override. No override yields > undesired behavior. > Hmm.. So it should rather be? public class Foo { ... public boolean equals( Object other ) { ... } } Thanks! I just learnt something. -- ilAn
From: Lew on 14 Jun 2010 16:11 Lew writes: >> The parent 'equals()' method typically is one of those "other methods >> with different semantics". The semantics of 'equals(Object)' will >> differ from that of 'equals(Foo)' without special care, i.e., an >> override of the former that invokes the latter. >> >> 'equals()' is typically called with an 'Object' argument, and >> therefore the overload will not be invoked. Things like collections >> depend on the method to have an override. No override yields >> undesired behavior. > ilan wrote: > Hmm.. So it should rather be? > > public class Foo > { > ... Use @Override here > public boolean equals( Object other ) > { > ... > } > } > The answer to your question depends on whether you want an override or an overload. In the case of 'equals()' you want an override, or both. For code that depends on an override, as with 'java.util.Set' and its use of 'equals()', there must be such an override to give the expected results. -- Lew
From: Simon Brooke on 14 Jun 2010 16:24 On Mon, 14 Jun 2010 11:38:41 -0700, Lew wrote: > If 'equals(Object)' is not overridden, then it likely returns 'false' > even for an argument where 'equals(Foo)' would return 'true' if it were > invoked on the '(Foo)' cast of that instance. Programs usually invoke > 'equals(Object)', not 'equals(Foo)', so you get results you don't > expect. OK, this is because selector-method resolution is done at compile time, not at run time as it would be in CLOS and in some other object oriented languages... yes? What you're saying is if I do Foo foo = new Foo(); Foo bar = foo; assert foo.equals( bar); will in this example invoke the variant of equals declared on class Foo with the signature equals( Foo f), but Foo foo = new Foo(); Object bar = foo; assert foo.equals( bar); will invoke some more generic variant of equals declared on Foo or some superclass of Foo with the signature equals( Object o). Have I understood you right? -- ;; Semper in faecibus sumus, sole profundam variat
From: Lew on 14 Jun 2010 16:55
Lew wrote: >> If 'equals(Object)' is not overridden, then it likely returns 'false' >> even for an argument where 'equals(Foo)' would return 'true' if it were >> invoked on the '(Foo)' cast of that instance. Programs usually invoke >> 'equals(Object)', not 'equals(Foo)', so you get results you don't >> expect. > Simon Brooke <stillyet+n...(a)googlemail.com> wrote: > OK, this is because selector-method resolution is done at compile time, > not at run time as it would be in CLOS and in some other object oriented > languages... yes? > I don't know anything about CLOS. It's not relevant anyway, nor are those other languages. > What you're saying is if I do > > Foo foo = new Foo(); > Foo bar = foo; > > assert foo.equals( bar); > > will in this example invoke the variant of equals declared on class Foo > with the signature equals( Foo f), but > > Foo foo = new Foo(); > Object bar = foo; > > assert foo.equals( bar); > > will invoke some more generic variant of equals declared on Foo or some > superclass of Foo with the signature equals( Object o). > > Have I understood you right? > Yes, barring the confusion with the Java-specific meaning of "generic". See the JLS as mentioned upthread: <http://java.sun.com/docs/books/jls/third_edition/html/ expressions.html#292575> -- Lew |