📄 tij309.htm
字号:
<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(Note n) {
System.out.println(<font color=#004488>"Percussion.play() "</font> + n);
}
<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(Note n) {
System.out.println(<font color=#004488>"Stringed.play() "</font> + n);
}
<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(Note n) {
System.out.println(<font color=#004488>"Brass.play() "</font> + n);
}
<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(Note n) {
System.out.println(<font color=#004488>"Woodwind.play() "</font> + n);
}
<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=#0000ff>private</font> <font color=#0000ff>static</font> Test monitor = <font color=#0000ff>new</font> Test();
<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(Note.MIDDLE_C);
}
<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) {
<font color=#009900>// Upcasting during addition to the array:</font>
Instrument[] orchestra = {
<font color=#0000ff>new</font> Wind(),
<font color=#0000ff>new</font> Percussion(),
<font color=#0000ff>new</font> Stringed(),
<font color=#0000ff>new</font> Brass(),
<font color=#0000ff>new</font> Woodwind()
};
tuneAll(orchestra);
monitor.expect(<font color=#0000ff>new</font> String[] {
<font color=#004488>"Wind.play() Middle C"</font>,
<font color=#004488>"Percussion.play() Middle C"</font>,
<font color=#004488>"Stringed.play() Middle C"</font>,
<font color=#004488>"Brass.play() Middle C"</font>,
<font color=#004488>"Woodwind.play() Middle C"</font>
});
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE><p><br></p>
<p>You can see that there’s really no change except in the base class. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap07_1054" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>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 intended to be used. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap07_1055" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h2>
<a name="_Toc375545338"></a><a name="_Toc24775664"></a><a name="Heading6439"></a>Constructors
and polymorphism</h2>
<p>As usual, constructors are different from other kinds of methods. This is also true when polymorphism is involved. Even though constructors are not polymorphic (they’re actually <a name="Index649"></a><a name="Index650"></a><b>static</b> methods, but the <b>static</b> declaration is implicit), it’s important to understand the way constructors work in complex hierarchies and with polymorphism. This understanding will help you avoid unpleasant entanglements. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap07_1056" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h3>
<a name="_Toc375545339"></a><a name="_Toc24775665"></a><a name="Heading6441"></a>Order
of constructor calls<br></h3>
<p><a name="Index651"></a><a name="Index652"></a>The order of constructor calls was briefly discussed in Chapter 4 and again in Chapter 6, but that was before polymorphism was introduced. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap07_1057" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>A constructor for the base class is always called during the construction process for a derived class, chaining up the inheritance hierarchy so that a constructor for every base class is called. This makes sense because the constructor has a special job: to see that the object is built properly. A derived class has access to its own members only, and not to those of the base class (whose members are typically <b>private</b>). Only the base-class constructor has the proper knowledge and access to initialize its own elements. Therefore, it’s essential that all constructors get called, otherwise the entire object wouldn’t be constructed. That’s why the compiler enforces a constructor call for every portion of a derived class. It will silently call the default constructor if you don’t explicitly call a base-class constructor in the derived-class constructor body. If there is no default constructor, the compiler will complain. (In the case where a class has no constructors, the compiler will automatically synthesize a default constructor.) <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap07_1058" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Let’s take a look at an example that shows the effects of composition, inheritance, and polymorphism on the order of construction:<br></p>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c07:Sandwich.java</font>
<font color=#009900>// Order of constructor calls.</font>
<font color=#0000ff>package</font> c07;
<font color=#0000ff>import</font> com.bruceeckel.simpletest.*;
<font color=#0000ff>class</font> Meal {
Meal() { System.out.println(<font color=#004488>"Meal()"</font>); }
}
<font color=#0000ff>class</font> Bread {
Bread() { System.out.println(<font color=#004488>"Bread()"</font>); }
}
<font color=#0000ff>class</font> Cheese {
Cheese() { System.out.println(<font color=#004488>"Cheese()"</font>); }
}
<font color=#0000ff>class</font> Lettuce {
Lettuce() { System.out.println(<font color=#004488>"Lettuce()"</font>); }
}
<font color=#0000ff>class</font> Lunch <font color=#0000ff>extends</font> Meal {
Lunch() { System.out.println(<font color=#004488>"Lunch()"</font>); }
}
<font color=#0000ff>class</font> PortableLunch <font color=#0000ff>extends</font> Lunch {
PortableLunch() { System.out.println(<font color=#004488>"PortableLunch()"</font>);}
}
<font color=#0000ff>public</font> <font color=#0000ff>class</font> Sandwich <font color=#0000ff>extends</font> PortableLunch {
<font color=#0000ff>private</font> <font color=#0000ff>static</font> Test monitor = <font color=#0000ff>new</font> Test();
<font color=#0000ff>private</font> Bread b = <font color=#0000ff>new</font> Bread();
<font color=#0000ff>private</font> Cheese c = <font color=#0000ff>new</font> Cheese();
<font color=#0000ff>private</font> Lettuce l = <font color=#0000ff>new</font> Lettuce();
<font color=#0000ff>public</font> Sandwich() {
System.out.println(<font color=#004488>"Sandwich()"</font>);
}
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
<font color=#0000ff>new</font> Sandwich();
monitor.expect(<font color=#0000ff>new</font> String[] {
<font color=#004488>"Meal()"</font>,
<font color=#004488>"Lunch()"</font>,
<font color=#004488>"PortableLunch()"</font>,
<font color=#004488>"Bread()"</font>,
<font color=#004488>"Cheese()"</font>,
<font color=#004488>"Lettuce()"</font>,
<font color=#004488>"Sandwich()"</font>
});
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE><p><br></p>
<p>This example creates a complex class out of other classes, and each class has a constructor that announces itself. The important class is <b>Sandwich</b>, which reflects three levels of inheritance (four, if you count the implicit inheritance from <b>Object</b>) and three member objects. You can see the output when a <b>Sandwich</b> object is created in <b>main( )</b>. This means that the order of constructor calls for a complex object is as follows: <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap07_1059" title="Send BackTalk Comment">Feedback</a></font><br></p>
<ol>
<li><a name="Index653"></a><a name="Index654"></a><a name="Index655"></a><a name="Index656"></a>The
base-class constructor is called. This step is repeated recursively such that
the root of the hierarchy is constructed first, followed by the next-derived
class, etc., until the most-derived class is reached. <font size="-2"><a
href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap07_1060" title="Send BackTalk
Comment">Feedback</a></font></li>
<li>Member initializers are called in the order of declaration. <font
size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]Chap07_1061"
title="Send BackTalk Comment">Feedback</a></font></li>
<li>The body of the derived-class constructor is called. <font size="-2"><a
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -