📄 chap07.htm
字号:
<backtalk:display ID=TIJ3_CHAPTER7_I27>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The output is:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>InstrumentX.play()</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This certainly doesn’t appear to be
a polymorphic method call. Once you understand what’s happening, you can
fix the problem fairly easily, but imagine how difficult it might be to find the
bug if it’s buried in a program of significant size.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I27'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER7_I28>
</FONT><A NAME="_Toc375545334"></A><A NAME="_Toc481064632"></A><BR></P></DIV>
<A NAME="Heading242"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Abstract classes <BR>and methods</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In all the instrument examples, the
methods in the base class <B>Instrument</B> were always “dummy”
methods. If these methods are ever called, you’ve done something wrong.
That’s because the intent of <B>Instrument</B> is to create a <I>common
interface</I> for all the classes derived from it.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I28'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER7_I29>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The only reason to establish this common
interface<A NAME="Index696"></A><A NAME="Index697"></A> is so it can be
expressed differently for each different subtype. It establishes a basic form,
so you can say what’s in common with all the derived classes. Another way
of saying this is to call <B>Instrument</B> an <I>abstract base class</I>
<A NAME="Index698"></A><A NAME="Index699"></A><A NAME="Index700"></A>(or simply
an <I>abstract class</I>). You create an abstract class when you want to
manipulate a set of classes through this common interface. All derived-class
methods that match the signature of the base-class declaration will be called
using the dynamic binding mechanism. (However, as seen in the last section, if
the method’s name is the same as the base class but the arguments are
different, you’ve got overloading, which probably isn’t what you
want.)
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I29'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER7_I30>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you have an abstract class like
<B>Instrument</B>, objects of that class almost always have no meaning. That is,
<B>Instrument</B> is meant to express only the interface, and not a particular
implementation, so creating an <B>Instrument</B> object makes no sense, and
you’ll probably want to prevent the user from doing it. This can be
accomplished by making all the methods in <B>Instrument</B> print error
messages, but that delays the information until run-time and requires reliable
exhaustive testing on the user’s part. It’s always better to catch
problems at compile-time.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I30'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER7_I31>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Java provides a mechanism for doing this
called the <I>abstract
method</I></FONT><A NAME="fnB37" HREF="#fn37">[37]</A><FONT FACE="Georgia">.
This is a method that is incomplete; it has only a declaration and no method
body. Here is the syntax for an abstract method declaration:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>abstract</font> <font color=#0000ff>void</font> f();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A class containing abstract methods is
called an <I>abstract class</I>. If a class contains one or more abstract
methods, the class must be qualified as <B>abstract</B>. (Otherwise, the
compiler gives you an error message.)
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I31'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER7_I32>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If an abstract class is incomplete, what
is the compiler supposed to do when someone tries to make an object of that
class? It cannot safely create an object of an abstract class, so you get an
error message from the compiler. This way the compiler ensures the purity of the
abstract class, and you don’t need to worry about misusing it.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I32'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER7_I33>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you
<A NAME="Index701"></A><A NAME="Index702"></A><A NAME="Index703"></A>inherit
from an abstract class and you want to make objects of the new type, you must
provide method definitions for all the abstract methods in the base class. If
you don’t (and you may choose not to), then the derived class is also
abstract and the compiler will force you to qualify <I>that</I> class with the
<A NAME="Index704"></A><B>abstract</B> keyword.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I33'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER7_I34>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It’s possible to create a class as
<B>abstract</B> without including any <B>abstract</B> methods. This is useful
when you’ve got a class in which it doesn’t make sense to have any
<B>abstract</B> methods, and yet you want to prevent any instances of that
class.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I34'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER7_I35>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>Instrument</B> class can easily be
turned into an <B>abstract</B> class. Only some of the methods will be
<B>abstract</B>, since making a class abstract doesn’t force you to make
all the methods <B>abstract</B>.<B> </B>Here’s what it looks
like:</FONT><BR></P></DIV>
<DIV ALIGN="CENTER"><FONT FACE="Georgia"><IMG SRC="TIJ217.gif"></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here’s the orchestra example
modified to use <B>abstract</B> classes and methods:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c07:music4:Music4.java</font>
<font color=#009900>// Abstract classes and methods.</font>
<font color=#0000ff>import</font> java.util.*;
<font color=#0000ff>abstract</font> <font color=#0000ff>class</font> Instrument {
<font color=#0000ff>int</font> i; <font color=#009900>// storage allocated for each</font>
<font color=#0000ff>public</font> <font color=#0000ff>abstract</font> <font color=#0000ff>void</font> play();
<font color=#0000ff>public</font> String what() {
<font color=#0000ff>return</font> <font color=#004488>"Instrument"</font>;
}
<font color=#0000ff>public</font> <font color=#0000ff>abstract</font> <font color=#0000ff>void</font> adjust();
}
<font color=#0000ff>class</font> Wind <font color=#0000ff>extends</font> Instrument {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> play() {
System.out.println(<font color=#004488>"Wind.play()"</font>);
}
<font color=#0000ff>public</font> String what() { <font color=#0000ff>return</font> <font color=#004488>"Wind"</font>; }
<font color=#0000ff>public</font> <font color=#0000ff>void</font> adjust() {}
}
<font color=#0000ff>class</font> Percussion <font color=#0000ff>extends</font> Instrument {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> play() {
System.out.println(<font color=#004488>"Percussion.play()"</font>);
}
<font color=#0000ff>public</font> String what() { <font color=#0000ff>return</font> <font color=#004488>"Percussion"</font>; }
<font color=#0000ff>public</font> <font color=#0000ff>void</font> adjust() {}
}
<font color=#0000ff>class</font> Stringed <font color=#0000ff>extends</font> Instrument {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> play() {
System.out.println(<font color=#004488>"Stringed.play()"</font>);
}
<font color=#0000ff>public</font> String what() { <font color=#0000ff>return</font> <font color=#004488>"Stringed"</font>; }
<font color=#0000ff>public</font> <font color=#0000ff>void</font> adjust() {}
}
<font color=#0000ff>class</font> Brass <font color=#0000ff>extends</font> Wind {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> play() {
System.out.println(<font color=#004488>"Brass.play()"</font>);
}
<font color=#0000ff>public</font> <font color=#0000ff>void</font> adjust() {
System.out.println(<font color=#004488>"Brass.adjust()"</font>);
}
}
<font color=#0000ff>class</font> Woodwind <font color=#0000ff>extends</font> Wind {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> play() {
System.out.println(<font color=#004488>"Woodwind.play()"</font>);
}
<font color=#0000ff>public</font> String what() { <font color=#0000ff>return</font> <font color=#004488>"Woodwind"</font>; }
}
<font color=#0000ff>public</font> <font color=#0000ff>class</font> Music4 {
<font color=#009900>// Doesn't care about type, so new types</font>
<font color=#009900>// added to the system still work right:</font>
<font color=#0000ff>static</font> <font color=#0000ff>void</font> tune(Instrument i) {
<font color=#009900>// ...</font>
i.play();
}
<font color=#0000ff>static</font> <font color=#0000ff>void</font> tuneAll(Instrument[] e) {
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < e.length; i++)
tune(e[i]);
}
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
Instrument[] orchestra = <font color=#0000ff>new</font> Instrument[5];
<font color=#0000ff>int</font> i = 0;
<font color=#009900>// Upcasting during addition to the array:</font>
orchestra[i++] = <font color=#0000ff>new</font> Wind();
orchestra[i++] = <font color=#0000ff>new</font> Percussion();
orchestra[i++] = <font color=#0000ff>new</font> Stringed();
orchestra[i++] = <font color=#0000ff>new</font> Brass();
orchestra[i++] = <font color=#0000ff>new</font> Woodwind();
tuneAll(orchestra);
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that there’s really no
change except in the base class.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I35'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER7_I36>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It’s helpful to create <B>abstract
</B>classes and methods because they make the abstractness of a class explicit,
and tell both the user and the compiler how it was
int<A NAME="_Toc375545338"></A>ended to be used.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I36'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER7_I37>
</FONT><A NAME="_Toc481064633"></A><BR></P></DIV>
<A NAME="Heading243"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Constructors and polymorphism</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As usual,
<A NAME="Index705"></A><A NAME="Index706"></A>constructors are different from
other kinds of methods. This is also true when polymorphism is involved. Even
though constructors are not polymorphic (although you can have a kind of
“virtual constructor,” as you will see in Chapter 12), it’s
important to understand the way constructors work in complex hierarchies and
with polymorphism. This understanding will help you avoid unpleasant
entanglements.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I37'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER7_I38>
</FONT><A NAME="_Toc375545339"></A><A NAME="_Toc481064634"></A><BR></P></DIV>
<A NAME="Heading244"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Order of constructor
calls<BR><A NAME="Index707"></A><A NAME="Index708"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The order of constructor calls was
briefly discussed in Chapter 4 and again in Chapter 6, but that was before
polymorphism was introduced.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I38'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER7_I39>
</FONT><BR></P></DIV>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -