📄 chapter07.html
字号:
– that is, there is no storage associated with an <B>interface
</B>–<B> </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="Index599"></A><A NAME="Index600"></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="Tjava111.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 and 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:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: 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 i = <font color=#0000ff>new</font> Hero();
t(i); <font color=#009900>// Treat it as a CanFight</font>
u(i); <font color=#009900>// Treat it as a CanSwim</font>
v(i); <font color=#009900>// Treat it as a CanFly</font>
w(i); <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.)</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>.</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.</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="Index601"></A><A NAME="Index602"></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.</FONT><A NAME="_Toc375545337"></A><A NAME="_Toc408018540"></A><BR></P></DIV>
<A NAME="Heading217"></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="Index603"></A><A NAME="Index604"></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>//: 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();
}
<font color=#0000ff>class</font> DragonZilla <font color=#0000ff>implements</font> DangerousMonster {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> menace() {}
<font color=#0000ff>public</font> <font color=#0000ff>void</font> destroy() {}
}
<font color=#0000ff>interface</font> Vampire
<font color=#0000ff>extends</font> DangerousMonster, Lethal {
<font color=#0000ff>void</font> drinkBlood();
}
<font color=#0000ff>class</font> HorrorShow {
<font color=#0000ff>static</font> <font color=#0000ff>void</font> u(Monster b) { b.menace(); }
<font color=#0000ff>static</font> <font color=#0000ff>void</font> v(DangerousMonster d) {
d.menace();
d.destroy();
}
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
DragonZilla if2 = <font color=#0000ff>new</font> DragonZilla();
u(if2);
v(if2);
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>DangerousMonster</B> is a simple
extension to <B>Monster</B> that produces a new <B>interface</B>. This is
implemented in <B>DragonZilla</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The syntax used in <B>Vampire</B>
works <I>only</I> when inheriting interfaces. Normally, you can use
<A NAME="Index605"></A><B>extends</B> with only a single class, but since an
<B>interface</B> can be made from multiple other interfaces, <B>extends</B> can
refer to multiple base interfaces when building a new <B>interface</B>. As you
can see, the <B>interface</B> names are simply separated with
commas.</FONT><A NAME="_Toc375545338"></A><A NAME="_Toc408018541"></A><BR></P></DIV>
<A NAME="Heading218"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Grouping constants</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because any fields you put into an
<B>interface</B> are automatically <B>static</B> and <B>final</B>, the
<B>interface</B> is a convenient tool for
<A NAME="Index606"></A><A NAME="Index607"></A>creating groups of constant
values, much as you would with an <B>enum</B> in C or C++. For
example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Months.java</font>
<font color=#009900>// Using interfaces to create groups of constants</font>
<font color=#0000ff>package</font> c07;
<font color=#0000ff>public</font> <font color=#0000ff>interface</font> Months {
<font color=#0000ff>int</font>
JANUARY = 1, FEBRUARY = 2, MARCH = 3,
APRIL = 4, MAY = 5, JUNE = 6, JULY = 7,
AUGUST = 8, SEPTEMBER = 9, OCTOBER = 10,
NOVEMBER = 11, DECEMBER = 12;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Notice the Java style of using all
uppercase letters (with underscores to separate multiple words in a single
identifier) for <B>static</B> <B>final</B> primitives that have constant
initializers – that is, for compile-time constants.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The fields in an <B>interface
</B>are automatically <B>public</B>, so it’s unnecessary to specify
that.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now you can use the constants from
outside the package by importing <B>c07.*</B> or <B>c07.Months</B> just as you
would with any other package, and referencing the values with expressions like
<B>Months.JANUARY</B>. Of course, what you get is just an <B>int</B> so there
isn’t the extra type safety that C++’s <B>enum</B> has, but this
(commonly-used) technique is certainly an improvement over hard-coding numbers
into your programs. (This is often referred to as using “magic
numbers” and it produces very difficult-to-maintain
code.)</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you do want extra type safety,
you can build a class like
this:</FONT><A NAME="fnB28" HREF="#fn28">[28]</A><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Month2.java</font>
<font color=#009900>// A more robust enumeration system</font>
<font color=#0000ff>package</font> c07;
<font color=#0000ff>public</font> <font color=#0000ff>final</font> <font color=#0000ff>class</font> Month2 {
<font color=#0000ff>private</font> String name;
<font color=#0000ff>private</font> Month2(String nm) { name = nm; }
<font color=#0000ff>public</font> String toString() { <font color=#0000ff>return</font> name; }
<font color=#0000ff>public</font> <font color=#0000ff>final</font> <font color=#0000ff>static</font> Month2
JAN = <font color=#0000ff>new</font> Month2(<font color=#004488>"January"</font>),
FEB = <font color=#0000ff>new</font> Month2(<font color=#004488>"February"</font>),
MAR = <font color=#0000ff>new</font> Month2(<font color=#004488>"March"</font>),
APR = <font color=#0000ff>new</font> Month2(<font color=#004488>"April"</font>),
MAY = <font color=#0000ff>new</font> Month2(<font color=#004488>"May"</font>),
JUN = <font color=#0000ff>new</font> Month2(<font color=#004488>"June"</font>),
JUL = <font color=#0000ff>new</font> Month2(<font color=#004488>"July"</font>),
AUG = <font color=#0000ff>new</font> Month2(<font color=#004488>"August"</font>),
SEP = <font color=#0000ff>new</font> Month2(<font color=#004488>"September"</font>),
OCT = <font color=#0000ff>new</font> Month2(<font color=#004488>"October"</font>),
NOV = <font color=#0000ff>new</font> Month2(<font color=#004488>"November"</font>),
DEC = <font color=#0000ff>new</font> Month2(<font color=#004488>"December"</font>);
<font color=#0000ff>public</font> <font color=#0000ff>final</font> <font color=#0000ff>static</font> Month2[] month = {
JAN, JAN, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC
};
<f
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -