📄 chapter06.html
字号:
}
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
Bath b = <font color=#0000ff>new</font> Bath();
b.print();
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Note that in the <B>Bath
</B>constructor a statement is executed before any of the initializations take
place. When you don’t initialize at the point of definition, there’s
still no guarantee that you’ll perform any initialization before you send
a message to an object handle – except for the inevitable run-time
exception.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here’s the output for the
program:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Inside Bath()
Soap()
s1 = Happy
s2 = Happy
s3 = Joy
s4 = Joy
i = 47
toy = 3.14
castille = Constructed</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When <B>print( )</B> is called
it fills in <B>s4</B> so that all the fields are properly initialized by the
time they are
used.</FONT><A NAME="_Toc305593252"></A><A NAME="_Toc305628724"></A><A NAME="_Toc312374015"></A><A NAME="_Toc375545307"></A><A NAME="_Toc408018510"></A><BR></P></DIV>
<A NAME="Heading181"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Inheritance syntax<BR><A NAME="Index433"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Inheritance is such an integral
part of Java (and OOP languages in general) that it was introduced in Chapter 1
and has been used occasionally in chapters before this one because certain
situations required it. In addition, you’re always doing inheritance when
you create a class, because if you don’t say otherwise you inherit from
Java’s standard root class <B>Object</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The syntax for composition is
obvious, but to perform inheritance there’s a distinctly different form.
When you inherit, you say “This new class is like that old class.”
You state this in code by giving the name of the class as usual, but before the
opening brace of the class body, put the <A NAME="Index434"></A>keyword
<B>extends</B> followed by the name of the
<A NAME="Index435"></A><A NAME="Index436"></A><I>base class</I>. When you do
this, you automatically get all the data members and methods in the base class.
Here’s an example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Detergent.java</font>
<font color=#009900>// Inheritance syntax & properties</font>
<font color=#0000ff>class</font> Cleanser {
<font color=#0000ff>private</font> String s = <font color=#0000ff>new</font> String(<font color=#004488>"Cleanser"</font>);
<font color=#0000ff>public</font> <font color=#0000ff>void</font> append(String a) { s += a; }
<font color=#0000ff>public</font> <font color=#0000ff>void</font> dilute() { append(<font color=#004488>" dilute()"</font>); }
<font color=#0000ff>public</font> <font color=#0000ff>void</font> apply() { append(<font color=#004488>" apply()"</font>); }
<font color=#0000ff>public</font> <font color=#0000ff>void</font> scrub() { append(<font color=#004488>" scrub()"</font>); }
<font color=#0000ff>public</font> <font color=#0000ff>void</font> print() { System.out.println(s); }
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
Cleanser x = <font color=#0000ff>new</font> Cleanser();
x.dilute(); x.apply(); x.scrub();
x.print();
}
}
<font color=#0000ff>public</font> <font color=#0000ff>class</font> Detergent <font color=#0000ff>extends</font> Cleanser {
<font color=#009900>// Change a method:</font>
<font color=#0000ff>public</font> <font color=#0000ff>void</font> scrub() {
append(<font color=#004488>" Detergent.scrub()"</font>);
<font color=#0000ff>super</font>.scrub(); <font color=#009900>// Call base-class version</font>
}
<font color=#009900>// Add methods to the interface:</font>
<font color=#0000ff>public</font> <font color=#0000ff>void</font> foam() { append(<font color=#004488>" foam()"</font>); }
<font color=#009900>// Test the new class:</font>
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
Detergent x = <font color=#0000ff>new</font> Detergent();
x.dilute();
x.apply();
x.scrub();
x.foam();
x.print();
System.out.println(<font color=#004488>"Testing base class:"</font>);
Cleanser.main(args);
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This demonstrates a number of
features. First, in the <B>Cleanser</B> <B>append( )</B> method,
<B>String</B>s are concatenated to <B>s</B> using the <B>+=</B> operator, which
is one of the operators (along with ‘<B>+</B>’) that the Java
designers “overloaded” to work with
<A NAME="Index437"></A><A NAME="Index438"></A><A NAME="Index439"></A><B>String</B>s.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Second, both <B>Cleanser</B> and
<B>Detergent</B> contain a <A NAME="Index440"></A><B>main( )</B> method.
You can create a <B>main( )</B> for each one of your classes, and
it’s often recommended to code this way so that your test code is wrapped
in with the class. Even if you have a lot of classes in a program only the
<B>main( )</B> for the <B>public</B> class invoked on the command line will
be called. (And you can have only one <B>public</B> class per file.) So in this
case, when you say <B>java Detergent</B>, <B>Detergent.main( )</B> will be
called. But you can also say <B>java Cleanser </B>to invoke
<B>Cleanser.main( )</B>, even though <B>Cleanser</B> is not a <B>public</B>
class. This technique of putting a <B>main( )</B> in each class allows easy
<A NAME="Index441"></A><A NAME="Index442"></A>unit testing for each class. And
you don’t need to remove the <B>main( )</B> when you’re
finished testing; you can leave it in for later testing.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here, you can see that
<B>Detergent.main( )</B> calls <B>Cleanser.main( )</B>
explicitly.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It’s important that all of
the methods in <B>Cleanser </B>are <B>public</B>. Remember that if you leave off
any access specifier the member defaults to “friendly,” which allows
access only to package members. Thus, within this package, anyone could use
those methods if there were no access specifier. <B>Detergent</B> would have no
trouble, for example. However, if a class from some other package were to
inherit <B>Cleanser</B> it could access only <B>public </B>members. So to plan
for inheritance, as a general rule make all fields <B>private </B>and all
methods <B>public. </B>(<B>protected </B>members also allow access by derived
classes; you’ll learn about this later.) Of course, in particular cases
you must make adjustments, but this is a useful guideline.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Note that <B>Cleanser</B> has a set
of methods in its interface: <B>append( )</B>, <B>dilute( )</B>,
<B>apply( )</B>, <B>scrub( )</B> and <B>print( )</B>. Because
<B>Detergent</B> is <I>derived from</I> <B>Cleanser</B> (via the
<A NAME="Index443"></A><B>extends</B> keyword) it automatically gets all these
methods in its interface, even though you don’t see them all explicitly
defined in <B>Detergent</B>. You can think of inheritance, then, as <I>reusing
the interface.</I> (The implementation comes along for free, but that part
isn’t the primary point.)</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As seen in <B>scrub( )</B>,
it’s possible to take a method that’s been defined in the base class
and modify it. In this case, you might want to call the method from the base
class inside the new version. But inside <B>scrub( )</B> you cannot simply
call <B>scrub( )</B>, since that would produce a recursive call, which
isn’t what you want. To solve this problem Java has the
<A NAME="Index444"></A>keyword <B>super</B> that refers to the
“<A NAME="Index445"></A>superclass” that the current class has been
inherited from. Thus the expression <B>super.scrub( )</B> calls the
base-class version of the method <B>scrub( )</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When inheriting you’re not
restricted to using the methods of the base class. You can also add new methods
to the derived class exactly the way you put any method in a class: just define
it. The <B>extends </B>keyword suggests that you are going to add new methods to
the base-class interface, and the method <B>foam( )</B> is an example of
this.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In <B>Detergent.main( )
</B>you can see that for a <B>Detergent</B> object you can call all the methods
that are available in <B>Cleanser</B> as well as in <B>Detergent </B>(i.e.
<B>foam( ))</B>.</FONT><A NAME="_Toc375545308"></A><A NAME="_Toc408018511"></A><BR></P></DIV>
<A NAME="Heading182"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Initializing the base
class<BR><A NAME="Index446"></A><A NAME="Index447"></A><A NAME="Index448"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Since there are now two classes
involved – the base class and the
<A NAME="Index449"></A><A NAME="Index450"></A>derived class – instead of
just one, it can be a bit confusing to try to imagine the resulting object
produced by a derived class. From the outside, it looks like the new class has
the same interface as the base class and maybe some additional methods and
fields. But inheritance doesn’t just copy the interface of the base class.
When you create an object of the derived class, it contains within it a
<I>subobject</I> of the base class. This
<A NAME="Index451"></A><A NAME="Index452"></A>subobject is the same as if you
had created an object of the base class by itself. It’s just that, from
the outside, the subobject of the base class is wrapped within the derived-class
object.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Of course, it’s essential
that the base-class subobject be initialized correctly and there’s only
one way to guarantee that: perform the initialization in the constructor, by
calling the base-class constructor, which has all the appropriate knowledge and
privileges to perform the base-class initialization. Java automatically inserts
calls to the base-class constructor in the derived-class constructor. The
following example shows this working with three levels of
inheritance:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Cartoon.java</font>
<font color=#009900>// Constructor calls during inheritance</font>
<font color=#0000ff>class</font> Art {
Art() {
System.out.println(<font color=#004488>"Art constructor"</font>);
}
}
<font color=#0000ff>class</font> Drawing <font color=#0000ff>extends</font> Art {
Drawing() {
System.out.println(<font color=#004488>"Drawing constructor"</font>);
}
}
<font color=#0000ff>public</font> <font color=#0000ff>class</font> Cartoon <font color=#0000ff>extends</font> Drawing {
Cartoon() {
System.out.println(<font color=#004488>"Cartoon constructor"</font>);
}
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
Cartoon x = <font color=#0000ff>new</font> Cartoon();
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The output for this program shows
the automatic calls:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Art constructor
Drawing constructor
Cartoon constructor</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that the construction
happens from the base “outward,” so the base class is initialized
before the derived-class constructors can access it.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Even if you don’t create a
constructor for <B>Cartoon( )</B>, the compiler will
<A NAME="Index453"></A>synthesize a default constructor for you that calls the
base class constructor.</FONT><BR></P></DIV>
<A NAME="Heading183"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Constructors with arguments</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The above example has default
<A NAME="Index454"></A>constructors; that is, they don’t have any
arguments. It’s easy for the compiler to call these because there’s
no question about what arguments to pass. If your class doesn’t have
default arguments or if you want to call a base-class constructor that has an
argument you must explicitly write the calls to the base-class constructor using
the <A NAME="Index455"></A><B>super</B> keyword and the appropriate argument
list:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Chess.java</font>
<font color=#009900>// Inheritance, constructors and arguments</font>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -