⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tij0082.html

📁 学习java的经典书籍
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<html><body>

<table width="100%"><tr>
<td>
<a href="http://www.bruceeckel.com/javabook.html">Bruce Eckel's Thinking in Java</a>
</td>
<td align="right">
<a href="tij_c.html">Contents</a> | <a href="tij0081.html">Prev</a> | <a href="tij0083.html">Next</a>
</td>
</tr></table>
<hr>

<H2 ALIGN=LEFT>
Constructors
and polymorphism
</H2>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">As
usual, <A NAME="Index675"></A><A NAME="Index676"></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 &#8220;virtual constructor,&#8221; as you will see in Chapter
11), it&#8217;s important to understand the way constructors work in complex
hierarchies and with polymorphism. This understanding will help you avoid
unpleasant entanglements.
</FONT><a name="_Toc375545339"></a><a name="_Toc408018554"></a><P></DIV>
<A NAME="Heading232"></A><H3 ALIGN=LEFT>
Order
of constructor calls
<P><A NAME="Index677"></A><A NAME="Index678"></A></H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
order of constructor calls was briefly discussed in Chapter 4, but that was
before inheritance and polymorphism were introduced. 
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">A
constructor for the base class is always called in the constructor for a
derived class, chaining upward 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 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>private</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">).
Only the base-class constructor has the proper knowledge and access to
initialize its own elements. Therefore, it&#8217;s essential that all
constructors get called, otherwise the entire object wouldn&#8217;t be
constructed properly. That&#8217;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&#8217;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><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Let&#8217;s
take a look at an example that shows the effects of composition, inheritance,
and polymorphism on the order of construction:
</FONT><P></DIV>

<font color="#990000"><PRE><font color="#009900">//: Sandwich.java</font>
<font color="#009900">// Order of constructor calls</font>

<font color="#0000ff">class</font> Meal {
  Meal() { System.out.println("Meal()"); }
}

<font color="#0000ff">class</font> Bread {
  Bread() { System.out.println("Bread()"); }
}

<font color="#0000ff">class</font> Cheese {
  Cheese() { System.out.println("Cheese()"); }
}

<font color="#0000ff">class</font> Lettuce {
  Lettuce() { System.out.println("Lettuce()"); }
}

<font color="#0000ff">class</font> Lunch <font color="#0000ff">extends</font> Meal {
  Lunch() { System.out.println("Lunch()");}
}

<font color="#0000ff">class</font> PortableLunch <font color="#0000ff">extends</font> Lunch {
  PortableLunch() {
    System.out.println("PortableLunch()");
  }
}

<font color="#0000ff">class</font> Sandwich <font color="#0000ff">extends</font> PortableLunch {
  Bread b = <font color="#0000ff">new</font> Bread();
  Cheese c = <font color="#0000ff">new</font> Cheese();
  Lettuce l = <font color="#0000ff">new</font> Lettuce();
  Sandwich() { 
    System.out.println("Sandwich()");
  }
  <font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) {
    <font color="#0000ff">new</font> Sandwich();
  }
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">This
example creates a complex class out of other classes, and each class has a
constructor that announces itself. The important class is 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Sandwich</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
which reflects three levels of inheritance (four, if you count the implicit
inheritance from 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">)
and three member objects. When a 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Sandwich</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object is created in 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>main(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
the output is:
</FONT><P></DIV>

<font color="#990000"><PRE>Meal()
Lunch()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()</PRE></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">This
means that the order of constructor calls for a complex object is as follows:
</FONT><P></DIV>
<OL>
<LI><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">	The
<A NAME="Index679"></A><A NAME="Index680"></A>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><LI><A NAME="Index681"></A><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">	<A NAME="Index682"></A>Member
initializers are called in the order of declaration.
</FONT><LI><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">	The
body of the derived-class constructor is called.
</FONT></OL><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
order of the constructor calls is important. When you inherit, you know all
about the base class and can access any 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>protected</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
members of the base class. This means that you must be able to assume that all
the members of the base class are valid when you&#8217;re in the derived class.
In a normal method, construction has already taken place, so all the members of
all parts of the object have been built. 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">I</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">nside
the constructor, however, you must be able to assume that all members that you
use have been built. The only way to guarantee this is for the base-class
constructor to be called first. Then when you&#8217;re in the derived-class
constructor, all the members you can access in the base class have been
initialized. &#8220;Knowing that all members are valid&#8221; inside the
constructor is also the reason that, whenever possible, you should initialize
all member objects (that is, objects placed in the class using composition) at
their point of definition in the class (e.g.: 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>b</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>c,</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>l</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in the example above). If you follow this practice, you will help ensure that
all base class members 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>and</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
member objects of the current object have been initialized. Unfortunately, this
doesn&#8217;t handle every case, as you will see in the next section.
</FONT><a name="_Toc408018555"></a><P></DIV>
<A NAME="Heading233"></A><H3 ALIGN=LEFT>
Inheritance
and finalize(&#160;)
</H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">When
you use composition to create a new class, you never worry about finalizing the
member objects of that class. Each member is an independent object and thus is <A NAME="Index683"></A>garbage
collected and finalized regardless of whether it happens to be a member of your
class. With inheritance, however, you must override <A NAME="Index684"></A><A NAME="Index685"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>finalize(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in the derived class if you have any special cleanup that must happen as part
of garbage collection. When you override 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>finalize(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in an inherited class, it&#8217;s important to remember to call the base-class
version of 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>finalize(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
since otherwise the base-class finalization will not happen. The following
example proves this:
</FONT><P></DIV>

<font color="#990000"><PRE><font color="#009900">//: Frog.java</font>
<font color="#009900">// Testing finalize with inheritance</font>

<font color="#0000ff">class</font> DoBaseFinalization {
  <font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">boolean</font> flag = <font color="#0000ff">false</font>;
}

<font color="#0000ff">class</font> Characteristic {
  String s;
  Characteristic(String c) {
    s = c;
    System.out.println(
      "Creating Characteristic " + s);
  }
  <font color="#0000ff">protected</font> <font color="#0000ff">void</font> finalize() {
    System.out.println(
      "finalizing Characteristic " + s);
  }
}

<font color="#0000ff">class</font> LivingCreature {
  Characteristic p = 
    <font color="#0000ff">new</font> Characteristic("is alive");
  LivingCreature() {
    System.out.println("LivingCreature()");
  }
  <font color="#0000ff">protected</font> <font color="#0000ff">void</font> finalize() {
    System.out.println(
      "LivingCreature finalize");
    <font color="#009900">// Call base-class version LAST!</font>
    <font color="#0000ff">if</font>(DoBaseFinalization.flag)
      <font color="#0000ff">try</font> {
        <font color="#0000ff">super</font>.finalize();
      } <font color="#0000ff">catch</font>(Throwable t) {}
  }
}

<font color="#0000ff">class</font> Animal <font color="#0000ff">extends</font> LivingCreature {
  Characteristic p = 
    <font color="#0000ff">new</font> Characteristic("has heart");
  Animal() {
    System.out.println("Animal()");
  }
  <font color="#0000ff">protected</font> <font color="#0000ff">void</font> finalize() {
    System.out.println("Animal finalize");
    <font color="#0000ff">if</font>(DoBaseFinalization.flag)
      <font color="#0000ff">try</font> {
        <font color="#0000ff">super</font>.finalize();
      } <font color="#0000ff">catch</font>(Throwable t) {}
  }
}

<font color="#0000ff">class</font> Amphibian <font color="#0000ff">extends</font> Animal {
  Characteristic p = 
    <font color="#0000ff">new</font> Characteristic("can live in water");
  Amphibian() {
    System.out.println("Amphibian()");
  }
  <font color="#0000ff">protected</font> <font color="#0000ff">void</font> finalize() {
    System.out.println("Amphibian finalize");
    <font color="#0000ff">if</font>(DoBaseFinalization.flag)
      <font color="#0000ff">try</font> {
        <font color="#0000ff">super</font>.finalize();
      } <font color="#0000ff">catch</font>(Throwable t) {}
  }
}

<font color="#0000ff">public</font> <font color="#0000ff">class</font> Frog <font color="#0000ff">extends</font> Amphibian {
  Frog() {
    System.out.println("Frog()");
  }
  <font color="#0000ff">protected</font> <font color="#0000ff">void</font> finalize() {
    System.out.println("Frog finalize");
    <font color="#0000ff">if</font>(DoBaseFinalization.flag)
      <font color="#0000ff">try</font> {
        <font color="#0000ff">super</font>.finalize();
      } <font color="#0000ff">catch</font>(Throwable t) {}
  }
  <font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -