Inheritance Inheritance is helpful in modeling hierarchies of concepts. It also facilitates code reuse by allowing one class

plumponionchipsΛογισμικό & κατασκευή λογ/κού

18 Νοε 2013 (πριν από 3 χρόνια και 11 μήνες)

64 εμφανίσεις

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
.