There is no difficulty with having an instantiable class add a value component while abiding by both the equals
class and the LSP, if the contract of the base class would allow derived classes to do so, and if the equals
method of the base class is coded in such a way as to either
Check the exact type of anything with which it is compared, and report false
if the exact types don't match.
Define a method which it uses as part of the equality-check process, and which a derived class can override as needed.
Using approach #1, any derived class may define equals
to consider new fields without creating any difficulty, since the only things to which a derived-class instance could possibly be considered equal would be other instances of that same derived class.
Using approach #2 is a bit trickier, but a simple approach might be to override equals
something to call a protected
equals2 method like this:
@override boolean equals(Object other)
{
if (!(other instanceof MyType)) return false;
MyType otherAsMyType = (MyType)other;
return this.equals1(OtherAsMyType) && OtherAsMyType.equals1(this) &&
this.equals2(OtherAsMyType) && OtherAsMyType.equals2(this);
}
The equals1
method of the derived type would return false
when passed something that wasn't derived from it, even if that other object knew nothing about the derived part; splitting the comparison into the different parts will ensure that if a type can quickly determine that an object of the other type cannot possibly be equal to it, the code in the first class won't waste time checking parts that seemingly could be equal.