• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Overriding equals for a subclass

 
Ranch Hand
Posts: 230
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
When overriding equals for a subclass, I'm assuming that super.equals should always be called, is this correct? If not, you could have an object whose subclass attributes are the same but are not really the same.

If you should always call super.equals, what do you do when the super class has not implemented equals (assuming you do not have access to modify the source)? There could be private variables you don't have access to so using getters is not always an option.

Thoughts on this?

Thanks,
Jeff
 
author and iconoclast
Posts: 24207
46
Mac OS X Eclipse IDE Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I would not say that there's a cut-and-dried rule about calling super.equals(). You certainly can call it, and use the result as needed. But you should always know in a particular case whether this makes sense or not.

There is, however, a general consensus that extending a concrete class is often the wrong thing to do, and if you have to extend a class that has its own implementation of equals(), you're on very thin ice. That's because generally, equals() is expected to be symmetric; if a.equals(b), then you expect b.equals(a), right? But what if a is a BaseClass instance, and b is a SubClass instance? BaseClass.equals(X) will almost certainly return true for instances of SubClass that have common parts equal. Should SubClass.equals(Y) ever return true if Y is an instance of BaseClass? Without much imagination, you can construct valid arguments both ways. Now what if Y is an instance of OtherSubClass? How do you write SubClass.equals() if there can be multiple subclasses? It's really a mess.
 
Ranch Hand
Posts: 1970
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It is common to call super.equals() but you have to consider carefully each case, unfortunately.

Of course, every class implements equals(), because Object does. However, not every class overrides the default implementation of equals() with a value-based equality test. The default implementation simply compares the object references for identity - do they point to the same object.

If an object does not provide a value-based equality test, it should generally be assumed that the class does not have a value that can validly be compared for equality.

If such a class is your superclass, and you know the class does not have a value at all (e.g. it's java.lang.Object), you can happily override equals() with your own value-based test, using only the data in your own class.

For superclasses that do have member data that could be considered to be a value, do not override the default identity test with a value-based test, but do provide public or protected access to their value, you can implement your own value test.

For the hopefully small minority of classes that do have member data that could be considered to be a value, do not override the default identity test with a value-based test, and do not provide access to their value, there is indeed a big problem. The solution, if indeed a valid solution exists, can only be considered on a case-by-case basis.

... and Ernest makes good points about the general dubiousness of overriding superclass's value-based equality test with your own. You have to decide carefully, on a case-by-case basis, if it's valid.
[ July 16, 2007: Message edited by: Peter Chase ]
 
Jeff Storey
Ranch Hand
Posts: 230
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I appreciate all of the input on this question. Basically, here's what I'm trying to do:

I have an abstract class A and a base classes B and C that extend this. Basically all of the attributes needed for comparison are in the abstract class, and the concrete classes provide some small details, more as a convenience to other programmers so they don't need to be constantly looking up what parameters to pass. A simple example would be something like this: I have an abstract class Car that takes one parameter, a Color. Every time I want a blue car, rather than calling new Car(Color.BLUE), I'd call new BlueCar(), which calls super(Color.BLUE). Now say some other programmer decides to creates a class called AnotherBlueCar which also calls new Car(Color.BLUE). In my mind, BlueCar and AnotherBlueCar should not be equals. Even though all of their attributes are equal, they are different classes of cars.

So what I want to do is have an equals method that says,

or


This checks that the two cars are semantically equal, not just equal in terms of their properties. Does that make sense?

Then I run into one other issue here. If this does make sense, how do I come up with a hashcode for BlueCar and AnotherBlueCar, since there are no attributes specific to the subclass, just the name of the class. Do I just use the super's hashcode?

Thanks again for the help.
Jeff
 
Ernest Friedman-Hill
author and iconoclast
Posts: 24207
46
Mac OS X Eclipse IDE Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The concrete superclass problem doesn't arise if the superclass is not concrete, as here -- so the problems I describe aren't a worry. Your equals() implementations are OK. For hashCode(), you need to make sure that the values obey the one ironclad rule: for two equal objects, the values must be equal. It doesn't matter if unequal objects have equal or unequal hashCode (although unequal is nice, if you can swing it.) As you've described things here, using super.hashCode() should be fine, as long as the superclass overrides it correctly so that it follows this rule itself.
 
Jeff Storey
Ranch Hand
Posts: 230
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks again. I've realized that after I made that post, in my previous example, I will allow BlueCar and AnotherBlueCar to be equals. For my actual code, I think it will be acceptable. I appreciate your help on this topic.
 
a wee bit from the empire
a bit of art, as a gift, the permaculture playing cards
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic