In
heritance
Inheritance
is helpful in
modeling hierarchies of
concepts.
It also
facilitates code
reuse by allowing one class
to extend the functionality
of another, so that the new
class doesn’t have to be
redefined from scratch.
We say that t
he new class
extends
, or inherits from,
the old class.
The new class is called a
subclass
(of a
superclass
).
In OO terms, instances of
a subclass should be able to
respond to all the messages
of the superclass, and more.
For example,
savings
accounts should be able to
respond to all of the
messages that bank
accounts can, plus a
n
a
dd
Interest
message
(and perhaps others).
This is done by defining a
SavingsAccount
class
to
be a subclass of the existing
BankAccount
class.
We have also a
lready seen
the inheritance of
BalloonComponent
and
other classes from
JComponent
.
And many library classes
(
JFrame
,
ArrayList
,
Graphics2D
,
etc.
)
extend
some superclass.
When a
subclass extends
a superclass, it inherits all
of the superclass meth
ods
and instance fields.
In particular, instances of
the subclass will be able to
respond to
all
legal
messages for the
superclass
.
For a given superclass
message, the subclass may
or may not define
its
own
method.
If it does, the
corresponding
superclass
method is said to be
overridden
.
Otherwise, the (inherited)
superclass method is
invoked automatically in
response to the message.
Overridden superclass
methods may be accessed
by qualifying them with the
keyword
super
.
The keywo
rd
super
may
also be used to invoke a
superclass constructor (cf.
pp. 378
-
9).
In this case,
super
must
be the first statement of the
subclass constructor.
Subclasses may define
new methods
–
corresponding to new
messages.
These new methods
are
not available to superclass
objects.
A subclass may define its
own instance fields.
These
fields are not
available to super
class
objects.
I
nstance fields of the
superclass should not be
redefined in the subclass
(cf. Common Error 10.2).
Subclass methods may
access
instance fields and
methods of the superclass if
they are
public
or
protected
, but not
if they
are
private
.
Note that
in
page 372
’s
SavingsAccount
class,
the
addInterest
method
can
no
t access the
private
balance field dir
ectly.
It uses
getBalance
and
deposit
instead.
E
xtending a class is
different from
implementing an interface.
I
nterface
s have
no
method definitions or
nonconstant instance fields
to inherit
.
T
hat is, there is no notion
of
state
, and no noti
on of
behavior
–
all that is
specified is what messages
need to be accepted.
S
uperclasses
need not
define
methods for all of the
messages that they accept.
Such classes (and their
undefined methods) are
said to be
abstract
, and
must be labeled as s
uch
.
M
ethod definitions for
abstract methods are left to
subclasses
(
cf. Advanced
Topic 10.1
)
.
The rules for converting
between subclasses and
superclasses
are similar to
th
ose
for
interfaces and
their
implementing classes.
The compiler needs t
o
check
that
an object c
an
respond to any message
that the program sends it.
But all it knows about a
variable is its declared type.
C
onversion
from a
subclass to a superclass
is
trivial
.
Conversion is the other
direction isn't allowed
without
a cast
--
e.g.,
SavingsAccount s =
new
BankAccount
(
…);
The problem is that
s
might be sent a savings
account message that it
couldn't respond to.
As with interfaces, if the
type conversion is not
possible, an exception will
be thrown at run ti
me.
Polymorphism is handled
essentially as for interfaces.
The method used to
respond to a message is
determined by the receiving
object's type
–
not the
declared type of the
corresponding variable.
The (run
-
time) type of a
value may be check
ed with
the
boolean
-
valued
instanceOf
operator.
Or
getClass
may be
used
--
cf. Special Topic
10.5.
T
he compiler must know
that
some
method will be
invoked in response to a
message.
So messages defined for a
subclass can
no
t be sent to
objects
declared to be of a
superclass
--
unless those
objects are cast to the
subclass
.
For example, on p. 381 of
the text,
anAccount
has
been declared as a
BankAccount
and thus
can’t be sent the
SavingsAccount
message
addInterest
.
Four different levels
of
protection exist in Java for
fields, methods, and classes.
Of these,
pr
otected
and
package
are of limited
usefulness.
Since
pr
otected
instance fields aren’t public
but are accessible to
subclasses, this level may
seem appropriate for, say,
the
balance
field in the
BankAccount
class.
However, the
pr
otected
instance fields
of a class are also accessible
to members of any other
class in the class’s package.
And any class may
declare itself to be a
member of any package.
The same objecti
on
applies to the default
(package) level of
protection.
Note that if a class is
inaccessible to another class
because the first class is
private, so are its public
fields and methods.
Inheritance is transitive
–
a subclass of a subclass of a
clas
s is a subclass of the
class.
All classes inherit,
directly or indirectly, from
a predefined class
O
bject
.
The
Object
class
defines
several
methods, such as
clone
,
toString
and
equals
.
In many cases these
predefined methods are
useless
, misle
ading,
or
even
dangerous for a class, and
so
should be redefined
by
the class
.
Library classes should
normally redefine
toString
,
equals
, and
clone
.
It’s often important for
other classes to do so as
well.
One reason for redefining
toString
is
for use in
debugging.
If you're tempted to p
rint
a message to
a
user,
consider instead having the
method return a
String
.
In defining a
toString
method for
a
class, the type
coercion that the string
operator
+
applies to its
arguments is often hel
pful.
It’s also often helpful to
use the static
toString
methods of wrapper classes.
You may expect the
classes in Sun’s Java
library to have appropriate
toString
methods.
The text’s suggestion for
defining
toString
for
classes that are expect
ed to
be superclasses is given as
Special
Topic 10.4.
User
-
defined classes often
need to override the
equals
method.
The
Object
class's
equals
method simply
calls the
==
operator.
This operator checks only
that the two values are
stored at the
same location.
In most cases, this is not
the desired behavior.
For example, Java’s
String
class redefines
equals
to compare
s
trings
character by character.
R
edefining
equals
generally requires a cast.
I
ssues involving casts and
potential
errors are covered
in Special Topic 10.5.
There are several
important issues that arise
when overriding inherited
methods.
First, if the argument
types don’t match exactly,
then the inherited method is
not overridden.
Instead, both the old and
new methods exist
simultaneously as
overloaded methods.
This can be a source of
considerable confusion (cf.
Common Error 10.6 on p.
395 of the text).
Second, it’s a compiler
error to attempt to override
with a more restrictive
access type
–
cf. C
ommon
Error 10.5 on p. 385 of the
text.
Finally, it’s occasionally
useful to override with a
less restrictive access type.
This helps in overriding
the
clone
method
–
cf.
Special Topic 10.6.
You aren’t responsible on
tests for knowing the det
ails
of how to override the
Object.clone
method.
You should know why it
can be important to do so.
Recall that assigning one
object variable to another
creates a new
reference
, but
not a new
object
.
This can be a problem,
since mutating the obj
ect
with one name mutates the
object with the other name
--
they’re the same object.
The
Object.clone
method goes (just) one step
beyond simple assignment.
It copies each of the
instance fields. That is, it
makes a
shallow copy
.
If these field
s are all of
nonclass type, there’s no
problem
–
the old object
and the new one share no
part of their structure.
If some are of nonclass
type and the rest are of
immutable types, there’s
again no problem.
Here there is some
structure sharing, but
no
mutator can modify either
structure.
But if some instance fields
are of a mutable type, then
the structure sharing does
allow one object to be
mutated by calling a
mutator on a component of
the other object.
This is the problem that
we are tryin
g to avoid.
That is, the same problem
reoccurs one level deeper.
To take control of the
cloning process, you need to
override
Object.clone
according to the
instruc
tions in Special
Topic 10.6.
Chapter 16
covers
Object.has
h
Code
.
Enter the password to open this PDF file:
File name:
-
File size:
-
Title:
-
Author:
-
Subject:
-
Keywords:
-
Creation Date:
-
Modification Date:
-
Creator:
-
PDF Producer:
-
PDF Version:
-
Page Count:
-
Preparing document for printing…
0%
Σχόλια 0
Συνδεθείτε για να κοινοποιήσετε σχόλιο