📄 tij0081.html
字号:
<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="tij0080.html">Prev</a> | <a href="tij0082.html">Next</a>
</td>
</tr></table>
<hr>
<H2 ALIGN=LEFT>
Inner
classes
</H2>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">In
Java 1.1<A NAME="Index611"></A>
it’s possible to place a class definition within another class
definition. This is called an
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>inner
class
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
The <A NAME="Index612"></A><A NAME="Index613"></A>inner
class is a useful feature because it allows you to group classes that logically
belong together and to control the visibility of one within the other. However,
it’s important to understand that inner classes are distinctly different
from composition.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Often,
while you're learning about them, the need for inner classes isn’t
immediately obvious. At the end of this section, after all of the syntax and
semantics of inner classes have been described, you’ll find an example
that should make clear the benefits of inner classes.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">You
create an inner class just as you’d expect: by placing the class
definition inside a surrounding class: (See page
<A HREF=" PAGE#Running_programs">97</A>
if you have trouble executing this program.)
</FONT><P></DIV>
<font color="#990000"><PRE><font color="#009900">//: Parcel1.java</font>
<font color="#009900">// Creating inner classes</font>
<font color="#0000ff">package</font> c07.parcel1;
<font color="#0000ff">public</font> <font color="#0000ff">class</font> Parcel1 {
<font color="#0000ff">class</font> Contents {
<font color="#0000ff">private</font> <font color="#0000ff">int</font> i = 11;
<font color="#0000ff">public</font> <font color="#0000ff">int</font> value() { <font color="#0000ff">return</font> i; }
}
<font color="#0000ff">class</font> Destination {
<font color="#0000ff">private</font> String label;
Destination(String whereTo) {
label = whereTo;
}
String readLabel() { <font color="#0000ff">return</font> label; }
}
<font color="#009900">// Using inner classes looks just like</font>
<font color="#009900">// using any other class, within Parcel1:</font>
<font color="#0000ff">public</font> <font color="#0000ff">void</font> ship(String dest) {
Contents c = <font color="#0000ff">new</font> Contents();
Destination d = <font color="#0000ff">new</font> Destination(dest);
}
<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) {
Parcel1 p = <font color="#0000ff">new</font> Parcel1();
p.ship("Tanzania");
}
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
inner classes, when used inside
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ship( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
look just like the use of any other classes. Here, the only practical
difference is that the names are nested within
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Parcel1</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
You’ll see in a while that this isn’t the only difference.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">More
typically, an outer class will have a method that returns a handle to an inner
class, like this:
</FONT><P></DIV>
<font color="#990000"><PRE><font color="#009900">//: Parcel2.java</font>
<font color="#009900">// Returning a handle to an inner class</font>
<font color="#0000ff">package</font> c07.parcel2;
<font color="#0000ff">public</font> <font color="#0000ff">class</font> Parcel2 {
<font color="#0000ff">class</font> Contents {
<font color="#0000ff">private</font> <font color="#0000ff">int</font> i = 11;
<font color="#0000ff">public</font> <font color="#0000ff">int</font> value() { <font color="#0000ff">return</font> i; }
}
<font color="#0000ff">class</font> Destination {
<font color="#0000ff">private</font> String label;
Destination(String whereTo) {
label = whereTo;
}
String readLabel() { <font color="#0000ff">return</font> label; }
}
<font color="#0000ff">public</font> Destination to(String s) {
<font color="#0000ff">return</font> <font color="#0000ff">new</font> Destination(s);
}
<font color="#0000ff">public</font> Contents cont() {
<font color="#0000ff">return</font> <font color="#0000ff">new</font> Contents();
}
<font color="#0000ff">public</font> <font color="#0000ff">void</font> ship(String dest) {
Contents c = cont();
Destination d = to(dest);
}
<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) {
Parcel2 p = <font color="#0000ff">new</font> Parcel2();
p.ship("Tanzania");
Parcel2 q = <font color="#0000ff">new</font> Parcel2();
<font color="#009900">// Defining handles to inner classes:</font>
Parcel2.Contents c = q.cont();
Parcel2.Destination d = q.to("Borneo");
}
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">If
you want to make an object of the inner class anywhere except from within a non-
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>static</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method of the outer class, you must specify the type of that object as
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>OuterClassName.InnerClassName</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
as seen in
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>main( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.</FONT><a name="_Toc408018544"></a><P></DIV>
<A NAME="Heading222"></A><H3 ALIGN=LEFT>
Inner
classes and upcasting
<P><A NAME="Index614"></A><A NAME="Index615"></A><A NAME="Index616"></A></H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">So
far, inner classes don’t seem that dramatic. After all, if it’s
hiding you’re after, Java already has a perfectly good hiding mechanism
– just allow the class to be “<A NAME="Index617"></A>friendly”
(visible only within a <A NAME="Index618"></A><A NAME="Index619"></A>package)
rather than creating it as an inner class.
</FONT><P></DIV><DIV ALIGN=LEFT><A NAME="Index620"></A><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">However,
inner classes really come into their own when you start upcasting to a base
class, and in particular to an
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>interface.</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
(The effect of producing an interface handle from an object that implements it
is essentially the same as upcasting to a base class.) That’s because the
inner class can then be completely unseen and unavailable to anyone, which is
convenient for hiding the implementation. All you get back is a handle to the
base class or the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>interface,</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and it’s possible that you can’t even find out the exact type, as
shown here:
</FONT><P></DIV>
<font color="#990000"><PRE><font color="#009900">//: Parcel3.java</font>
<font color="#009900">// Returning a handle to an inner class</font>
<font color="#0000ff">package</font> c07.parcel3;
<font color="#0000ff">abstract</font> <font color="#0000ff">class</font> Contents {
<font color="#0000ff">abstract</font> <font color="#0000ff">public</font> <font color="#0000ff">int</font> value();
}
<font color="#0000ff">interface</font> Destination {
String readLabel();
}
<font color="#0000ff">public</font> <font color="#0000ff">class</font> Parcel3 {
<font color="#0000ff">private</font> <font color="#0000ff">class</font> PContents <font color="#0000ff">extends</font> Contents {
<font color="#0000ff">private</font> <font color="#0000ff">int</font> i = 11;
<font color="#0000ff">public</font> <font color="#0000ff">int</font> value() { <font color="#0000ff">return</font> i; }
}
<font color="#0000ff">protected</font> <font color="#0000ff">class</font> PDestination
<font color="#0000ff">implements</font> Destination {
<font color="#0000ff">private</font> String label;
<font color="#0000ff">private</font> PDestination(String whereTo) {
label = whereTo;
}
<font color="#0000ff">public</font> String readLabel() { <font color="#0000ff">return</font> label; }
}
<font color="#0000ff">public</font> Destination dest(String s) {
<font color="#0000ff">return</font> <font color="#0000ff">new</font> PDestination(s);
}
<font color="#0000ff">public</font> Contents cont() {
<font color="#0000ff">return</font> <font color="#0000ff">new</font> PContents();
}
}
<font color="#0000ff">class</font> Test {
<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) {
Parcel3 p = <font color="#0000ff">new</font> Parcel3();
Contents c = p.cont();
Destination d = p.dest("Tanzania");
<font color="#009900">// Illegal -- can't access private class:</font>
<font color="#009900">//! Parcel3.PContents c = p.new PContents();</font>
}
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Now
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Contents</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Destination</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
represent interfaces available to the client programmer. (The
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>interface</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
remember, automatically makes all of its members
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public.</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">)
For convenience, these are placed inside a single file, but ordinarily
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Contents</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Destination</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
would each be
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">in
their own files.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">In
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Parcel3</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
something new has been added: the inner class
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>PContents</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>private
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">so
no one but
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Parcel3</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
can access it.
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>PDestination</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -