Re: Why this overloading example works this way?
"Patricia Shanahan" <pats@acm.org> wrote in message
news:8gAeh.8457$tM1.1028@newsread1.news.pas.earthlink.net...
Oliver Wong wrote:
...
*: Actually, making equals "aware" of class hierarchies is slightly
trickier than that. I wanted to gloss over this in my above example, but
here's a more complete example implementation:
public class SomeClass {
final int field1;
final String field2;
/*Constructors, getters, and hashcode*/
@Override
public boolean equals(Object other) {
if (other instanceof SomeClass) {
return equals((SomeClass)other);
}
return false;
}
public boolean equals(SomeClass other) {
if (!other.getClass().equals(this.getClass())) {
return other.equals(this);
}
if (this.field1 != other.field1) {
return false;
}
if (!this.field2.equals(other.field2)) {
return false;
}
return true;
}
}
I got worried about whether this code would ever make up its mind, given a
subclass comparison. It doesn't:
public class SomeClass {
final int field1 = 0;
final String field2 = "test";
public static void main(String[] args) {
Object obj1 = new SomeClass();
Object obj2 = new SomeSubClass();
System.out.println(obj1.equals(obj2));
}
/*Constructors, getters, and hashcode*/
@Override
public boolean equals(Object other) {
if (other instanceof SomeClass) {
return equals((SomeClass)other);
}
return false;
}
public boolean equals(SomeClass other) {
if (!other.getClass().equals(this.getClass())) {
return other.equals(this);
}
if (this.field1 != other.field1) {
return false;
}
if (!this.field2.equals(other.field2)) {
return false;
}
return true;
}
private static class SomeSubClass extends SomeClass{
}
}
This program results in a StackOverflowError. obj1 passes the comparison
to obj2, which passes it back to obj1... What am I doing wrong? Are
subclasses of SomeClass required to override equals with specific rules?
The SomeSubClass must override equals(SomeClass) to define how the
subclass participates in the equality check. The idea is that classes tend
to know about their superclasses, but not their subclasses, so when
comparing for equality between two objects, the one whose class is a
subclass of the other should be "controlling" the comparison.
Consider data structures like (the following is pseudo-Java):
public Struct Point {
int x, y;
}
public Struct Point3D extends Point{
int z;
}
And for our given problem domain, we say a Point3D is only equal to a
Point if the x and y coordinates match, and if the z coordinate of the
Point3D is 0.
Rather than putting this extra logic in Point, it would probably make
more sense to put it in Point3D, but if you don't provide the subclass check
in Point, then these two calls to Equals will probably give inconsistent
results:
Point p = /*get somehow*/;
Point3D p3d = /*get somehow*/;
p.equals(p3d);
p3d.equals(p);
So I always put that subclass check, so that I am (or others are) free
to later on provide a subclass which may introduce new rules to the way
equals works across related classes.
- Oliver