Java Reference
In-Depth Information
not only if the variable refers to that type, but also if it refers to any of its subclasses.
Consider the following test in the
equals
method of the
Point
class:
if (o instanceof Point) {
...
}
The test will evaluate to
true
if
o
refers to a
Point
object or a
Point3D
object.
The
instanceof
operator is like an is-a test, asking whether the variable refers to
any type that can fill the role of a
Point
. By contrast,
Point3D
's
equals
method
tests whether the parameter is an instance of
Point3D
and rejects it if it is not. A
Point
cannot fill the role of a
Point3D
(not every
Point
is a
Point3D
), so the
method will return
false
if the parameter is of type
Point
.
Consequently, the
equals
behavior is not symmetric when it is used with a mixture
of
Point
and
Point3D
objects. The following client code demonstrates the problem:
Point p = new Point(12, 7);
Point3D p3d = new Point3D(12, 7, 11);
System.out.println("p.equals(p3d) is " + p.equals(p3d));
System.out.println("p3d.equals(p) is " + p3d.equals(p));
The code produces the output that follows. The first test returns
true
because a
Point
can accept a
Point3D
as the parameter to
equals
, but the second test returns
false
because a
Point3D
cannot accept a
Point
as its parameter to
equals
:
p.equals(p3d) is true
p3d.equals(p) is false
This is a problem, because the contract of the
equals
method requires it to be a
symmetric operation. You'd encounter other problems if you added more behavior to
Point3D
, such as a
setLocation
or
distance
method.
Proper object-oriented design would not allow
Point3D
to extend
Point
, because
any code that asks for a
Point
object should be able to work correctly with a
Point3D
object as well. We call this principle
substitutability.
(It is also sometimes
called the Liskov substitution principle, in honor of the Turing Award-winning author
of a 1993 paper describing the idea.)
Substitutability
The ability of an object of a subclass to be used successfully anywhere an
object of the superclass is expected.
Fundamentally, a
Point3D
isn't the same thing as a
Point
, so an is-a relationship
with inheritance is the wrong choice. In this case, you're better off writing
Point3D
from scratch and avoiding these thorny issues.
Search WWH ::
Custom Search