mafalda
mafalda

Reputation: 1024

Base class does not define equals but sub-class needs to. How to implement?

I don't have access to the base class code. But need to be able to define equals in sub-class that also take some base class properties into consideration.

Additionally the base class does not have protected fields. All fields are accessible only through accessors/mutators.

Would it be considered bad to just do comparisions of the base class fields in my sub-class equals ? Why ?

I need to do this because my base class has a default equals that does not work for my purpose but it also has fields that need to be taken into consideration when doing a sub-class equals...

Upvotes: 3

Views: 404

Answers (4)

Matthew Gilliard
Matthew Gilliard

Reputation: 9498

Yes, you can do this, there won't be any problems calling the getters in your superclass as you can determine equality any way you want, so long as you follow the contract:

Reflexive: x.equals(x) should return true.

Symmetric: x.equals(y) == y.equals(x)

Transitive: x.equals(y) && y.equals(z) => x.equals(z)

Consistent: Multiple invocations of x.equals(y) consistently return true or false unless x or y is mutated between calls.

And the equals-hashcode contract:

Equal objects must have equal hashcodes

http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#equals(java.lang.Object)

Upvotes: 6

DJClayworth
DJClayworth

Reputation: 26876

There is nothing particularly wrong with overriding equals, and certainly nothing wrong with accessing private methods through their getters if that is what you need to do.

However there is a slight conceptual issue here, related to the Liskov Substitution principle, which states that you should be able to substitute a child class for a base class and not get any conceptual change of behaviour.

If the equals() you implement is conceptually very different from the equals implemented in the base class, then people using your code (such as maintainers) will find it hard to understand. They will code based on certain assumptions and those assumptions will turn out to be wrong. For example if the base equals() is based on reference equality, i.e.

equals(Object o) { return this == o;}

and your implementation does something very different, users will need to know more about the specific implemntation than they should. It will also violate symmetricality: x.equals(y) won't be the same as y.equals(x) if x is your child class and y the base class.

That being said none of these are insurmountable, and if you can't modify the base you may not have a choice. Add lots of comments to your class.

Upvotes: 0

David Moles
David Moles

Reputation: 51153

There should be no problem, provided you also override hashCode(), and provided the properties in question are immutable.

An equals() method that sometimes returns true and sometimes returns false, depending on whether someone has called setXXX() in the mean time, is a very dangerous thing -- it can't be used for much of what equals() is good for, such as determining membership in a collection.

If equals() is really what you need -- in order to work with other APIs like java.util.Collections -- then I suggest overriding the mutators to throw UnsupportedOperationException. If not, your equals() method will be unreliable. See for example: How to use two numbers as a Map key

If you can't -- e.g. if the mutators are final -- then I wouldn't even try subclassing. Instead, I'd copy the values from the 'superclass' object into my own fields, and then throw the original away. (If you keep it around, even as a private field, you can't count on somebody else not having a reference to it and mutating it.) If you need your 'subclass' to interoperate with APIs that require the 'superclass', then include an asXXX() method that generates the "superclass" object on the fly.

Otherwise, if you just need to determine equivalency for your own purposes, I wouldn't override equals()/hashCode() at all, but instead create a new method, and call it something like isEquivalentTo().

Upvotes: 0

Mac
Mac

Reputation: 14791

That is entirely reasonable. There's nothing wrong with taking into consideration properties inherited from a base class when doing comparisons of a derived class. Essentially, when you are comparing two objects all that is important is whether they are the same by some definition of your choosing, regardless of where the information for that comparison comes from. Use whatever you need.

Upvotes: 2

Related Questions