📄 chap08.htm
字号:
}
<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">The rest of the code works the same. It
doesn’t matter if you are <A NAME="Index761"></A>upcasting to a
“regular” class called <B>Instrument</B>, an <B>abstract</B> class
called <B>Instrument</B>, or to an <A NAME="Index762"></A><B>interface</B>
called <B>Instrument</B>. The behavior is the same. In fact, you can see in the
<B>tune( )</B> method that there isn’t any evidence about whether
<B>Instrument</B> is a “regular” class, an <B>abstract</B> class, or
an <B>interface</B>. This is the intent: Each approach gives the programmer
different control over the way objects are created and used.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER8_I8'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER8_I9>
</FONT><A NAME="_Toc375545336"></A><A NAME="_Toc481064644"></A><BR></P></DIV>
<A NAME="Heading254"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
“Multiple inheritance” in Java</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>interface</B> isn’t simply a
“more pure” form of <B>abstract</B> class. It has a higher purpose
than that. Because an <B>interface</B> has no implementation at all—that
is, there is no storage associated with an <B>interface—</B>there’s
nothing to prevent many <B>interface</B>s from being combined. This is valuable
because there are times when you need to say “An <B>x</B> is an <B>a</B>
<I>and</I> a <B>b</B> <I>and</I> a <B>c</B>.” In C++, this act of
combining multiple class interfaces is called
<A NAME="Index763"></A><A NAME="Index764"></A><I>multiple inheritance</I>, and
it carries some rather sticky baggage because each class can have an
implementation. In Java, you can perform the same act, but only one of the
classes can have an implementation, so the problems seen in C++ do not occur
with Java when combining multiple interfaces:</FONT><BR></P></DIV>
<DIV ALIGN="CENTER"><FONT FACE="Georgia"><IMG SRC="TIJ224.gif"></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In a derived class, you aren’t
forced to have a base class that is either an <B>abstract</B> or
“concrete” (one with no <B>abstract</B> methods). If you <I>do</I>
inherit from a non-<B>interface</B>,<B> </B>you can inherit from only one. All
the rest of the base elements must be <B>interface</B>s. You place all the
interface names after the <B>implements </B>keyword and separate them with
commas. You can have as many <B>interface</B>s as you want—each one
becomes an independent type that you can upcast to. The following example shows
a concrete class combined with several <B>interface</B>s to produce a new class:
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER8_I9'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER8_I10>
</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c08:Adventure.java</font>
<font color=#009900>// Multiple interfaces.</font>
<font color=#0000ff>import</font> java.util.*;
<font color=#0000ff>interface</font> CanFight {
<font color=#0000ff>void</font> fight();
}
<font color=#0000ff>interface</font> CanSwim {
<font color=#0000ff>void</font> swim();
}
<font color=#0000ff>interface</font> CanFly {
<font color=#0000ff>void</font> fly();
}
<font color=#0000ff>class</font> ActionCharacter {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> fight() {}
}
<font color=#0000ff>class</font> Hero <font color=#0000ff>extends</font> ActionCharacter
<font color=#0000ff>implements</font> CanFight, CanSwim, CanFly {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> swim() {}
<font color=#0000ff>public</font> <font color=#0000ff>void</font> fly() {}
}
<font color=#0000ff>public</font> <font color=#0000ff>class</font> Adventure {
<font color=#0000ff>static</font> <font color=#0000ff>void</font> t(CanFight x) { x.fight(); }
<font color=#0000ff>static</font> <font color=#0000ff>void</font> u(CanSwim x) { x.swim(); }
<font color=#0000ff>static</font> <font color=#0000ff>void</font> v(CanFly x) { x.fly(); }
<font color=#0000ff>static</font> <font color=#0000ff>void</font> w(ActionCharacter x) { x.fight(); }
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
Hero h = <font color=#0000ff>new</font> Hero();
t(h); <font color=#009900>// Treat it as a CanFight</font>
u(h); <font color=#009900>// Treat it as a CanSwim</font>
v(h); <font color=#009900>// Treat it as a CanFly</font>
w(h); <font color=#009900>// Treat it as an ActionCharacter</font>
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that <B>Hero</B> combines the
concrete class <B>ActionCharacter</B> with the interfaces <B>CanFight</B>,
<B>CanSwim</B>, and <B>CanFly</B>. When you combine a concrete class with
interfaces this way, the concrete class must come first, then the interfaces.
(The compiler gives an error otherwise.)
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER8_I10'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER8_I11>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Note that the signature for
<B>fight( )</B> is the same in the <B>interface CanFight</B> and the class
<B>ActionCharacter</B>, and that <B>fight( )</B> is <I>not</I> provided
with a definition in <B>Hero</B>. The rule for an <B>interface</B> is that you
can inherit from it (as you will see shortly), but then you’ve got another
<B>interface</B>. If you want to create an object of the new type, it must be a
class with all definitions provided. Even though <B>Hero</B> does not explicitly
provide a definition for <B>fight( )</B>, the definition comes along with
<B>ActionCharacter</B> so it is automatically provided and it’s possible
to create objects of <B>Hero</B>.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER8_I11'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER8_I12>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In class <B>Adventure</B>, you can see
that there are four methods that take as arguments the various interfaces and
the concrete class. When a <B>Hero</B> object is created, it can be passed to
any of these methods, which means it is being upcast to each <B>interface</B> in
turn. Because of the way interfaces are designed in Java, this works without a
hitch and without any particular effort on the part of the programmer.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER8_I12'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER8_I13>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Keep in mind that the core reason for
interfaces is shown in the above example: to be able to upcast to more than one
base type. However, a second reason for using interfaces is the same as using an
<B>abstract </B>base class: to prevent the client programmer from making an
object of this class and to establish that it is only an interface. This brings
up a question: Should you use an
<A NAME="Index765"></A><A NAME="Index766"></A><B>interface</B> or an
<B>abstract</B> class? An <B>interface</B> gives you the benefits of an
<B>abstract</B> class <I>and</I> the benefits of an <B>interface</B>, so if
it’s possible to create your base class without any method definitions or
member variables you should always prefer <B>interface</B>s to <B>abstract</B>
classes. In fact, if you know something is going to be a base class, your first
choice should be to make it an <B>interface</B>, and only if you’re forced
to have method definitions or member variables should you change to an
<B>abstract</B> class, or if necessary a concrete class.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER8_I13'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER8_I14>
</FONT><BR></P></DIV>
<A NAME="Heading255"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Name collisions when combining
interfaces<BR><A NAME="Index767"></A><A NAME="Index768"></A></H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can encounter a small pitfall when
implementing multiple interfaces. In the above example, both <B>CanFight</B> and
<B>ActionCharacter</B> have an identical <B>void fight( )</B> method. This
is no problem because the method is identical in both cases, but what if
it’s not? Here’s an example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c08:InterfaceCollision.java</font>
<font color=#0000ff>interface</font> I1 { <font color=#0000ff>void</font> f(); }
<font color=#0000ff>interface</font> I2 { <font color=#0000ff>int</font> f(<font color=#0000ff>int</font> i); }
<font color=#0000ff>interface</font> I3 { <font color=#0000ff>int</font> f(); }
<font color=#0000ff>class</font> C { <font color=#0000ff>public</font> <font color=#0000ff>int</font> f() { <font color=#0000ff>return</font> 1; } }
<font color=#0000ff>class</font> C2 <font color=#0000ff>implements</font> I1, I2 {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> f() {}
<font color=#0000ff>public</font> <font color=#0000ff>int</font> f(<font color=#0000ff>int</font> i) { <font color=#0000ff>return</font> 1; } <font color=#009900>// overloaded</font>
}
<font color=#0000ff>class</font> C3 <font color=#0000ff>extends</font> C <font color=#0000ff>implements</font> I2 {
<font color=#0000ff>public</font> <font color=#0000ff>int</font> f(<font color=#0000ff>int</font> i) { <font color=#0000ff>return</font> 1; } <font color=#009900>// overloaded</font>
}
<font color=#0000ff>class</font> C4 <font color=#0000ff>extends</font> C <font color=#0000ff>implements</font> I3 {
<font color=#009900>// Identical, no problem:</font>
<font color=#0000ff>public</font> <font color=#0000ff>int</font> f() { <font color=#0000ff>return</font> 1; }
}
<font color=#009900>// Methods differ only by return type:</font>
<font color=#009900>//! class C5 extends C implements I1 {}</font>
<font color=#009900>//! interface I4 extends I1, I3 {} ///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The difficulty occurs because overriding,
implementation, and overloading get unpleasantly mixed together, and overloaded
functions cannot differ only by return type. When the last two lines are
uncommented, the error messages say it all:</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><I>InterfaceCollision.java:23: f() in C
cannot implement f() in I1; attempting to use incompatible return type
</I></FONT><BR><FONT FACE="Georgia"><I>found :
int</I></FONT><BR><FONT FACE="Georgia"><I>required:
void</I></FONT><BR><FONT FACE="Georgia"><I>InterfaceCollision.java:24:
interfaces I3 and I1 are incompatible; both define f(), but with different
return type</I></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Using the same method names in different
interfaces that are intended to be combined generally causes confusion in the
readability of the code, as well. Strive to avoid it.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER8_I14'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER8_I15>
</FONT><A NAME="_Toc375545337"></A><A NAME="_Toc481064645"></A><BR></P></DIV>
<A NAME="Heading256"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Extending an interface <BR>with inheritance</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can easily add new method
declarations to an
<A NAME="Index769"></A><A NAME="Index770"></A><B>interface</B> using
inheritance, and you can also combine several <B>interface</B>s into a new
<B>interface</B> with inheritance. In both cases you get a new <B>interface</B>,
as seen in this example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c08:HorrorShow.java</font>
<font color=#009900>// Extending an interface with inheritance.</font>
<font color=#0000ff>interface</font> Monster {
<font color=#0000ff>void</font> menace();
}
<font color=#0000ff>interface</font> DangerousMonster <font color=#0000ff>extends</font> Monster {
<font color=#0000ff>void</font> destroy();
}
<font color=#0000ff>interface</font> Lethal {
<font color=#0000ff>void</font> kill();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -