Thinking in Java 3 Edition 致读者: 我从2002年7月开始翻译这本书,当时还是第二版。但是翻完前言和介绍部分 后, chinapub就登出广告,说要出版侯捷的译本。于是我中止了翻译,等着侯 先生的作品。 我是第一时间买的这本书,但是我失望了。比起第一版,我终于能看懂这本书 了,但是相比我的预期,它还是差一点。所以当 Bruce eckel在他的网站上公开 本书的第三版的时候,我决定把它翻译出来 说说容易,做做难。一本1000多页的书不是那么容易翻的。期间我也曾打过退 堂鼓,但最终还是全部翻译出来了。从今年的两月初起,到7月底,我几乎放 弃了所有的业余时间,全身心地投入本书的翻译之中。应该说,这项工作的难 度超出了我的想像 首先,读一本书和翻译一本书完全是两码事。英语与中文是两种不同的语言, 用英语说得很畅的句子,翻成中文之后就完全破了相。有时我得花好几分钟, 用中文重述一句我能用几秒钟读懂的句子。更何况作为读者,一两句话没搞 懂,并不影响你理解整本书,但对译者来说,这就不一样了。 其次,这是一本讲英语的人写给讲英语的人的书,所以同很多要照顾非英语读 者的技术文档不同,它在用词,句式方面非常随意。英语读者会很欣赏这 点,但是对外国读者来说,这就是负担了 再有, Bruce eckel这样的大牛人,写了1000多页,如果都让你读懂,他岂不是 太没面子?所以,书里还有一些很有“禅意”的句子。比如那句著名的“The genesis of the computer revolution was in a machine. The genesis of our programming languages thus tends to look like that machine.”我就一直没吃准该怎 么翻译。我想大概没人能吃准,说不定 Bruce要的就是这个效果。 这是一本公认的名著,作者在技术上的造诣无可挑剔。而作为译者,我的编程 能力差了很多。再加上上面讲的这些原因,使得我不得不格外的谨慎。当我重 读初稿的时候,我发现需要修改的地方实在太多了。因此,我不能现在就公开 全部译稿,我只能公开已经修改过的部分。不过这不是最终的版本,我还会继 续修订的。 本来,我准备到10月份,等我修改完前7章之后再公开。但是,我发现我又有 点要放弃了,因此我决定给自己一点压力,现在就公开。以后,我将修改完 章就公开一章,请关注www.wgggh.com/shags/tij.html。 如果你觉得好,请给告诉我,你的鼓励是我工作的动力:如果你觉得不好,那 就更应该告诉我了,我会参考你的意见作修改的。我希望能通过这种方法,译 出一本配得上原著的书 shags 3年9月8日 第1页共47页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com
Thinking in Java 3 rd Edition 1 ✁ ✂ 47 ✁ www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com 2002 7 chinapub !"#$%!&'( )*+,-.& /0(12 345( 67,893:);8(?@AB3CDE Bruce Eckel FG(HIJK (L(MNOPA!Q $$RSTTU3 1000 VW(XYZRS(@4[\]^_ `ab:c!Q,d(ef9g 7 hijk l,Dm(no4cpqrst (u*vw$ xy1(U z{!,(|} ~/3 3 ce* eX( $(* uc,>mi * 3;i=(13e =X ¡¢£¤ ¥Q$ X3¦, §¨ 3 ©(ª«¬©(ª(DEV%®¯ (°± ²XAF³´µ¶¯·¸¹º»¼ 3 C¥½¾Q$ ¿À, ÁmBruce Eckel ¦(Âê«, 1000 VWÄÅÆÇ¡=GÈX É¶Ê DEËm3ÌmÍιÏ(8ÄYÐÑ(ÍThe genesis of the computer revolution was in a machine. The genesis of our programming languages thus tends to look like that machine.Ï3ÒÓÔwÕ Z|ÂÖª;ÓÔ$XO Bruce %( ×ØÅ 3 KÙ(ÑÐ1F°±J(ÚÛÜÝÞßà1(áâ ;ãB,VÁäJJ¶©( ÌåæçXXè½(éê fë(Mìíî%ïð(rµñFÉV,æòX;íFK cëó;Kôõïð^(X^ Xb:( ºö ÷ïø( QÔùg 10 ú-ïð 7 ûuÁKìíüm C%kl,æòNO¬ýþ3CãíFKEïð3 ûK3û www.wgqqh.com/shhgs/tij.html ÄÅ¡¬#¡(ay1( ã ÄÅ¡XY vw#,º¡(¹ 1ïð(7;^ µ !3 JåÐ( shhgs 2003 9 8
Thinking in Java 3 Edition 8:接口与内部类 接口( interface)和内部类( inner class)提供了一种更为复杂的组织和控 制系统中对象的方法。 比方说,C++就没有这种机制,不过聪明的程序员还是能模拟出这种效 果。Java之所以会有这个特性,是因为设计人员认为它非常重要,语言 应该直接用关键词提供支持。 你已经在第7章学过了 abstract关键词,它能让你在类里创建一个或 多个没有定义的方法—你给出了接口,但是留一部分没做定义,这部分 要由它的继承类来定义。而 interface关键词则创建了一种完全抽象 的,根本不提供实现的类。你会看到, interface不仅是一种抽象类的 极端表现形式,它还是一种能让你将一个对象上传到多个基类的手段,因 此它提供了类似C++的“多重继承( multiple inheritance)”的功能 初看起来,内部类像是一种简单的隐藏代码的机制:你只是把一个类放到 另一个类里。但是,你将会看到,内部类可没这么简单—它还知道该怎 样同宿主类( surrounding class)打交道——因此,即使很多人还不熟悉 内部类,你还是能用它写出更为优雅清晰的代码。你得过一段时间才能把 内部类熟练地运用到设计之中。 接口( interface) interface关键词进一步强化了 abstract的概念。你可以把它想像成 纯的” abstract类。它能让开发人员定义类的形式:方法名,参数列 表,返回值的类型,但是却没有方法的正文。 interface也可以包含数 据成员,但是它天生就是 static和 final的。 interface只提供形式, 不谈实现 interface的意思是“所有‘实现’这个接口的类都应该长这个样 子。”因此任何程序,只要用到了这个 interface就都知道它有那些方 法可供调用了,仅此而已。因此, interface会被用作定义类之间的 “协议( protocol)”。(有些面向对象的语言真的用 protoco/关键词来作 这件事 要想创建 interface,只要把 class关键词换成 interface就行了。跟 类一样,你可以在 interface关键词前面加上 public(只有保存在同名 文件里的 interface才可以加),或者把它空着,留给它 package权 限,这样它就只能用于同一个 package了。 要创建一个实现了某个(或者某组) interface的类,就必须使用 implements关键词。它的意思是,“ interface要告诉你‘类长什么 第2页共47页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com
Thinking in Java 3 rd Edition www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com 2 ✁ ✂ 47 ✁ 8: (interface)(inner cl ass),3( *¥!(µ 8µ$C+ + m "X^#$(â%&;'(! Ø ÅJava uDEºm ×)*æ+,ª&ÙA¯·% vwÒ-³./ ¡ôõF 7 û0^, abstract -³A;Ç¡FË123×3 V×mO4(µ55¡¬!,63TO4 %7A(ö8QO4à in terface -³912,3c:! (; Xñí(¡º?í@´A3;Ç¡3×¥!JAgV×B(CDæ òA,E C+ + (ÍVö8(m u ltip l e inh eritance)Ï(F; f<9Q}3GH(IJK("L¡óP3×kg M3×Ë¡º<gÝ ZGH55ANOwÕ ¦PQ(su rrou nd ing cl ass)]RO55æòSçVªXTU ¡;A«!VWXY(K¡^3D4Z;P T[r\g+,u* (interface) in terface -³]3^_`, abstract (Öa¡ÝEPA|} Íb(Ïabstract A;Çìª&O4(@´LµÑcd ?efg(himµ(j in terface [ÝEklc m&An0 static final(in terface ó@´ Xoñí in terface (¹pÍDmq ñír ×(Ævws צ Ïæòtâ%ó%g, × in terface ÆNOAmY̵ Ýu,<òàôæòin terface ºv1O4u4( Íwx(p rotocol )Ï(m̶y¥!(z( protocol -³Q1 {) %|12 in terfaceó%P class -³| in terface },~ 3¦¡ÝEF in terface -³¶äJ pu blic(ómFÑ {Ë( in terface ZÝEä )3PA.6¬A package ¦Aó;)3× package , %123×ñí,×(3)in terface ( ç impl emen ts -³A(¹pÍin terface %#¡q sZ
Thinking in Java 3 Edition 样子’,但是现在我要告诉你‘它是怎样『工作」的’。”除此之外,它 同继承没什么两样。还是以乐器为例,下面的图演示了这种的关系: nterface Instrument d play o; String what: d adjust: implements implements implements Percussion Stringed void play o void playo void play o String what()String what String what( void adjust) void adjust void adjus机 nds xtends Woodwind r void play o void playo String what void adjust) 可以从 Woodwind和 Brass看出,类一旦实现了某个 interface 它就变成了一个可以再继承下去的普通类了。 你可以把 interface里的方法声明成 public的,但是即便不讲,它们 也是 public的。所以当你 implements一个 interface的时候,你 必须把这个 interface的方法定义成 public的。如果你不这么做,那 它就会变成 package权限的,这样经过继承,这些方法的访问权限就会 受到限制,而这是Java的编译器所不允许的 可以从修改后的 Instrument例程中看到这一点。注意,编译器只允许 你在 interface里面声明方法。此外,虽然 nstrument的方法都没 有被声明成 public的,但是它们自动都是 public的 // c08: musics: Music5. jav. / Interfaces package c08. music5i import com. bruceeckel. simpletest* import c07 music. Notei interface Instrument i 第3页共47页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com
Thinking in Java 3 rd Edition ✄ 3 ☎ ✆ 47 ☎ www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com ¦r íF%#¡q AÕ¦ y1 (r Ïòu½A ö8Ze¦E¶(, (L ÝE Woodwin d Brass <!3ñí,× in terface A,3×ÝEÁö8(, ¡ÝEP in terface Ë(µ$ pu blic (SX©A [ pu blic (DE ¡ impl emen ts 3× in terface (M¡ P × in terface (µO4 pu blic (ÄÅ¡X ZTY Aº package ( ¦õ^ö8 ̵(º gà Java (áDX( ÝEïð( In strumen t â*<g 3C¹áó ¡F in terface ˶$µò½ In strumen t (µÆ mv$ pu blic (Aý Æ pu blic (L //: c08:music5:Music5.java // Interfaces. package c08.music5; import com.bruceeckel.simpletest.*; import c07.music.Note; interface Instrument {
Thinking in Java 3 Edition // Compile-time constant int I =5: // static final / Cannot have method definitions void play(Note n)i// Automatically public String what ()i void adjust() public void p lements Instrument play(Note n)( printin("Wind. play()"+ n)i public String what()t return "wind"i 1 public void adjust()( class Percussion implements Instrument i public void play(Note n) System. out. println("Percussion. play () n); public String what ()t return "Percussion"i publ id adjust()i] class Stringed implements Instrument t public void play(Note n)t System. out. println("stringed play() public string what ()i return "Stringed"i j d adjust((] class Brass extends wind I public void play (Note n) t System. out. println("Brass. play() publ id adjust()i System. out. println("Brass. adjust ()")i class Woodwind extends wind i public void play(Note n)i System. out. println("Woodwind. play()+ n) public string what ()t return Woodwind"i j public class Musics t private static Test monitor new Test () Doesn't care about type, so new types / added to the system still work right static void tune(Instrument i)( 1. play(Note. MIDDLE_C) static void tuneAll(Instrument[] e) for(int i=0; i<elength; i++) 第4页共47页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com
Thinking in Java 3 rd Edition www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com ✄ 4 ☎ ✆ 47 ☎ // Compile-time constant: int I = 5; // static & final // Cannot have method definitions: void play(Note n); // Automatically public String what(); void adjust(); } class Wind implements Instrument { public void play(Note n) { System.out.println("Wind.play() " + n); } public String what() { return "Wind"; } public void adjust() {} } class Percussion implements Instrument { public void play(Note n) { System.out.println("Percussion.play() " + n); } public String what() { return "Percussion"; } public void adjust() {} } class Stringed implements Instrument { public void play(Note n) { System.out.println("Stringed.play() " + n); } public String what() { return "Stringed"; } public void adjust() {} } class Brass extends Wind { public void play(Note n) { System.out.println("Brass.play() " + n); } public void adjust() { System.out.println("Brass.adjust()"); } } class Woodwind extends Wind { public void play(Note n) { System.out.println("Woodwind.play() " + n); } public String what() { return "Woodwind"; } } public class Music5 { private static Test monitor = new Test(); // Doesn't care about type, so new types // added to the system still work right: static void tune(Instrument i) { // ... i.play(Note.MIDDLE_C); } static void tuneAll(Instrument[] e) { for(int i = 0; i < e.length; i++) tune(e[i]); }
Thinking in Java 3 Edition public static void main(string[ args)t / Upcasting during addition to the array new Percussion(), new Stringed() new Woodwind( monitor. expect (new String[] t Wind. play() Middle C", ercussion. play () Middle C Stringed play() Middle c Brass. play ( Middle C 其它代码的工作方式没变。不论是把它上传到一个叫 Instrument的 普通”类,还是一个叫 Instrument的 abstract类,还是一个叫 Instrument的 interface,它的工作方式都是一样的。实际上,你根 本没法从tune()来判断,工 nstrument到底是“普通”类,还是 abstract类,或 interface。这就是它的本意:它让程序员自己去选择 要在那个级别上控制对象的创建和使用。 Java的“多重继承” interface不仅仅是一种“更纯”的 abstract类。它还有更高一层的 目的。由于 interface不带任何“实现”—也就是说 interface和内 存无关—因此不会有谁去组绕 interface之间的结合。这一点非常重 要,因为有时你会遇到“x既是a又是b,而且还是c”的情况。在 C++中,这种“将多个类的接口结合在一起”的行为被称作“多重继承 ( multiple inheritance)”,但是由于每个类又都有它自己的实现,而这 会带来很多“甩都甩不掉”的问题。Java能让你作同样的事情,但是这 时只有一个类可以有实现,因此当你合并Java接口的时候,就不会有这 种问题了 第5页共47页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com
Thinking in Java 3 rd Edition ✄ 5 ☎ ✆ 47 ☎ www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com public static void main(String[] args) { // Upcasting during addition to the array: Instrument[] orchestra = { new Wind(), new Percussion(), new Stringed(), new Brass(), new Woodwind() }; tuneAll(orchestra); monitor.expect(new String[] { "Wind.play() Middle C", "Percussion.play() Middle C", "Stringed.play() Middle C", "Brass.play() Middle C", "Woodwind.play() Middle C" }); } } ///:~ §AK(y1µ´X PAJAg3ס In strumen t ( ÍÏ3ס In strumen t ( abstract 3ס In strumen t ( in terfaceA(y1µ´Æ3¦(ñ¢J¡; tu n e( )Q£¤In strumen t ghÍÏ abstract 3 in terface A( ¹LAÇâ%&ýþ¥¦ %FYק¨J¥!(12ç Java in terface X<<3ÍbÏ( abstract Am©3ª( «(7) in terface X¬tÍñíÏ55[$ in terface Ü55æòXºm® in terface u4(¯° 3C¯· %æm¡º±gÍx ² a ü bà³ cÏ(´F C+ + * ÍV×(¯°F39Ï(}vµ1ÍVö8 (multiple inheritance)Ï7)¶×üÆmAýþ(ñíà º¬QVÍ·Æ·X¸Ï(¹Java ;Ç¡1¦(´ óm3×ÝEmñíæò ¡° Java (MXºm ¹,L
Thinking in Java 3 Edition Abstract or Concrete interface 1 Base d ass interface erface n Base Class Methods interface 1 interface 2.. interface n ava并不强制你一定要去继承 abstract还是“具体”的类(就是不带 abstract方法的类),但是你只能继承一个非 interface的类。所有别 的基类元素( base elements)都必须是 interface。你得把所有的接口 名字都放在 implements关键词后面,用逗号把它们分开。你可以根据 需要,实现任意多个 interface;也可以将这个类上传至任何一个 interface。下面这段程序演示了如何将一个具体的类同几个 interface合并起来,创建一个新的类 Multiple interfaces interface CanFight void fight ( interface CanSwim interface CanFly void fly( class Actioncharacter public void fight()() class hero extends Actioncharacter implements CanFight, CanSwim, CanFly t public void swim()() public void fly()i public class Adventure t public static void t(CanFight x)(x fight ()i public static void u(CanSwim x)i public static void v(CanFly x)(x fly(i 1 public static void w(Actioncharacter x) ght()i J public static void main(String[] args)t ero lew Hero t(h)i// Treat it as a CanFight u(h)i// Treat it as a Canswim 第6页共47页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com
Thinking in Java 3 rd Edition www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com ✄ 6 ☎ ✆ 47 ☎ Java X_¡3O%ö8 abstract ͺ»Ï((X¬ abstract µ()¡ó;ö83ׯ in terface (Dm¨ (B¼½(base el em ents)Æ in terface¡PDm( ѾÆkF impl emen ts -³¶¿ÀPA¡ÝE;m î%ñít¹V× in terface [ÝE ×JAÁt3× in terface¶ Dâ%,Ä3׺»(i× in terface °9Q123×Â(L //: c08:Adventure.java // Multiple interfaces. interface CanFight { void fight(); } interface CanSwim { void swim(); } interface CanFly { void fly(); } class ActionCharacter { public void fight() {} } class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly { public void swim() {} public void fly() {} } public class Adventure { public static void t(CanFight x) { x.fight(); } public static void u(CanSwim x) { x.swim(); } public static void v(CanFly x) { x.fly(); } public static void w(ActionCharacter x) { x.fight(); } public static void main(String[] args) { Hero h = new Hero(); t(h); // Treat it as a CanFight u(h); // Treat it as a CanSwim
Thinking in Java 3 Edition v(h); Treat it as a canFly w(h); Treat it as an Actioncharacter 可以看到,Hero合并了具体的 Action character类,以及 Can Fight, Can swin和 Can Fly接口。当你用这种方式合并实体类 ( concrete class)和接口的时候,必须将实体类放在前面,然后才是接 口。(否则编译器就会报错。) 注意 Action character类的 fight()方法。它的特征与 interface Can Fight的 fight()方法完全相同,但是Hero没有提供fght()的 定义。 interface的规则是这样的,你可以继承它(马上就会说到),但 是继承下来的还是 interface。如果你想创建一个新类型的对象,那么 这个类型就必须是类,而且还得提供所有定义。尽管Hero没有明确的提 供 fight()的定义,但是 Action character提供了,所以Hero能自 动获得这个方法,并且能创建对象了 Adventure类有四个拿接口和实体类作参数的方法。创建出来的Hero 对象可以被传给其中任何一个方法,也就是说它被依次上传给了各个 interface。这个过程不需要程序员编写特别的代码,这一切要归功于接 口在Java中的设计。 上述程序告诉我们接口的真正目的:能够上传到多个基本类型(base type)。然而,使用接口的第二个理由,实际上是和“把 abstract类用 做基类”完全相同的:就是要禁止客户程序员去创建这个类的对象,并且 重申“这只是一个接口”。这就带来了一个问题:到底是用 interface,还是用 abstract类? interface既给了你 abstract类 的好处,又给了你 interface的好处,因此只要基类的设计里面可以不 包括方法和成员变量的定义,你就应该优先使用 interface。实际上, 如果你知道这样东西可能会是基类的话,你就应该优先考虑把它做成 interface,只有在不得不定义方法或成员变量的情况下,你才能把它改 成 abstract类,或者根据需要改成实体类。 合并接口时的名字冲突 实现多个接口的时候可能会遇到一些小问题。在上述例程中, Can Fight 和 Action character都有一个一摸一样的 void fight()方法。这里 没有问题,因为它们使用的是同一个方法。但是如果不是呢?下面就是 个例子: //: c08: Interfacecollision. java interface Il void f(i interface I2 int f(int i)i] 第7页共47页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com
Thinking in Java 3 rd Edition ✄ 7 ☎ ✆ 47 ☎ www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com v(h); // Treat it as a CanFly w(h); // Treat it as an ActionCharacter } } ///:~ ÝE H ero m figh t( )( O4in terface (È9 ¦(¡ÝEö8A(ÉJº$g ) ö8Q( in terfaceÄÅ¡|123×Âh(¥!YZ ×h à³DmO4ÊË H ero m$Ì( figh t( )(O4 Action Character ,DE H ero ;ý Í ×µ³;12¥!, Adven tu re mÎ×Ïñ»1c(µ12!Q( H ero ¥!ÝEvA¬§*t3×µ[$AvШJA¬,Ñ× in terface ×^âXî%â%&á«)¨(K 3Ò%ÓF) F Java *(+, Jâ%#(zj«(L;ÔJAgV×B h(base type)àç(×¢7ñ¢JÍP abstract TBÏc>(L%Õ+Ö×â%&12 ×(¥!³ ØÍ ó3×Ï ¬Q,3×¹Lgh in terface abstract Ê in terface ²¬,¡ abstract (Ùü¬,¡ in terface (Ùæòó%B(+,˶ÝEX kÚµ&Û(O4¡vwV/ç in terfaceñ¢J ÄÅ¡NO ¦ÜÝÝ;ºB(¡vwV/ÞPAT in terfaceómFXXO4µ3&Û(´¡Z;PAð abstract 3;mî%ðñ» ñíV×(MÝ;º±g3Ìß¹FJâ*Can F igh t Action Character Æm3×3à3¦( void figh t( )µ Ë m¹æAç(3×µÄÅXáÊ ¶3 ×L //: c08:InterfaceCollision.java interface I1 { void f(); } interface I2 { int f(int i); }
Thinking in Java 3 Edition interface I3 int f()i) class ct public int f() return li 1 class C2 implements Il, I2 public void f()I public int f(int i)i return l;// overloaded class C3 extends c implements I2 public int f(int i) return l; ) / overloaded } class C4 extends c implements I3 / Identical, no probl public int f() return 1 / Methods differ only by return type //! class C5 extends c implements I1 t // interface I4 extends Il, I3///: N 这个难题要归因于覆写、实现和重载的不期而遇,以及“不能仅通过返回 值来辨别重载的方法”。如果把最后两行的注释去掉,就会出现如下的错 误信息 Interface Collision java: 23: f() in C cannot implement f() in Ii; attempting to use incompatible return type found: int required: void Interface Collision java: 24: interfaces 13 and I1 are incompatible; both define f( but with different return type 而且在要合并的接口里面放上同名方法,通常也会破坏程序的可读性。所 以别这么做 用继承扩展 interface 你可以用继承,往 interface里面添加新的方法,也可以用继承把多个 interface合并成一个新的 interface。在这两种情况下,你所得到的 都只是一个新的 interface,就像下面这样: //: c08: Horrorshow. java / Extending an interface with inheritance nterface Monster i interface DangerousMonster extends Monster i void destroy()i 第8页共47页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com
Thinking in Java 3 rd Edition www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com ✄ 8 ☎ ✆ 47 ☎ interface I3 { int f(); } class C { public int f() { return 1; } } class C2 implements I1, I2 { public void f() {} public int f(int i) { return 1; } // overloaded } class C3 extends C implements I2 { public int f(int i) { return 1; } // overloaded } class C4 extends C implements I3 { // Identical, no problem: public int f() { return 1; } } // Methods differ only by return type: //! class C5 extends C implements I1 {} //! interface I4 extends I1, I3 {} ///:~ ×U¹%Óæ)â«ã ñíä(X@à±EÃÍX;<^ef gQå¨ä(µÏÄÅPbe}(渺!íÄ(Æ çèéL InterfaceCollision. java: 23: f( ) in C cannot implement f( ) in I1 ; attempting to use incompatible return type found : int required: void InterfaceCollision. java: 24: interfaces I3 and I1 are incompatible; both define f( ), but with different return type à³F%°(˶kJѵ·[ºêâ%(Ý*D E¨ ZT i n terface ¡ÝEö8ë in terface ˶ìäÂ(µ[ÝEö8PV× in terface °3×Â( in terfaceF e´¡Dg( Æó3×Â( interface}¶ ¦L //: c08:HorrorShow.java // Extending an interface with inheritance. interface Monster { void menace(); } interface DangerousMonster extends Monster { void destroy(); }
Thinking in Java 3 Edition terface lethal void kill( class DragonZilla implements DangerousMonster i public void menace()i) public void destroy()i] interface Vampire extends DangerousMonster, Letha void drinkBlood ( class VeryBadVampire implements Vampire t public void menace() public void destroy()IH public void kill()() public void drinkBlood()[] public class HorrorShow i static void u(Monster b)i b. menace(i static void v(DangerousMonster d)i d ddestroy()i static w( Letha11){1.ki11(); public c void main(string[ args) t Dange monster barney new DragonZilla()i u(barney)i v(barney) Vampire vlad new VeryBadVampire( u(vlad)i v(vlad) w(vlad)i DangerousMonster只是对 Monster做了一点扩展,然后生成一个 新的 interface。 Dragonzilla则实现了这个接口 Vampire的语法是“接口继承( inheriting interfaces)”所独有的。通 常情况下, extends只能用于类,但是由于一个 interface可以由多 个接口拼接而成,因此创建新的 interface的时候可以用 extends来 表示其多个“基接口( base interfaces)”。正如你所看到的 interface的名字要由逗号分隔 常量的分组 由于 interface的数据成员自动就是 static和 final的,因此 interface是一种非常方便的,创建一组常量值的工具。这点同C和 C++的enum很相似。例如: 第9页共47页 www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com
Thinking in Java 3 rd Edition ✄ 9 ☎ ✆ 47 ☎ www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com interface Lethal { void kill(); } class DragonZilla implements DangerousMonster { public void menace() {} public void destroy() {} } interface Vampire extends DangerousMonster, Lethal { void drinkBlood(); } class VeryBadVampire implements Vampire { public void menace() {} public void destroy() {} public void kill() {} public void drinkBlood() {} } public class HorrorShow { static void u(Monster b) { b.menace(); } static void v(DangerousMonster d) { d.menace(); d.destroy(); } static void w(Lethal l) { l.kill(); } public static void main(String[] args) { DangerousMonster barney = new DragonZilla(); u(barney); v(barney); Vampire vlad = new VeryBadVampire(); u(vlad); v(vlad); w(vlad); } } ///:~ Dan gerou sM on ster ó¥ M on ster T,3Cíî03× Â( in terfaceDragon Zil la 9ñí, × Vampire (Íö8(inh eriting interfaces)ÏDïm( ·´ exten ds ó;)7)3× in terface ÝE7V ×ðàæò12Â( in terface (MÝE exten ds Q ?§V×ÍB (base interfaces)ÏjÄ¡DEÄL
Thinking in Java 3 Edition //: c08: Months. java // Using interfaces to create groups of constant package c08; public interface Months i JANUARY = 1, FEBRUARY =2, MARCH =3, APRIL 4, MAY = 5, JUNE JULY AUGUST =8, SEPTEMBER =9, OCTOBER =10 NOVEMBER =11, DECEMBER =12; }///: 注意一下,Java的编程风格是,用全部大写字母(用下划线分隔同一个标 识符里的各个单词)来表示,用常量进行初始化的 static fina变量 nterface的数据成员自动就是 public的,因此就不必再注明了。 你可以像对待别的 package那样,用 import c08*或者 c08 Months把它引进来,这样就能在这个 package的外面用 Months JANUARY之类的表达式来使用这些常量了。当然,你得到的 是一个int,因此它没有像C++的enum那样的类型安全,但是这种 (很常见的)手法要比直接在程序里面用数字要好得多。(这种方法通常被 成为使用“神奇数字”,并且使得代码的维护变得非常困难。) 如果你确实需要额外的类型安全,可以像这样创建一个类:③3 // A more robust enumeration system public final class Month t t() private string name; private Month(String nm) name nm; 1 public string tostring( return name public static final Month JAN new Month("January ") FEB new Month("February") MAR new Month("March"), nth(Al AY new Month("May") JUN new Month("June " JUL Month("July " AUG new Month("August " SEP new Month("September") OCT new Month("October") NOV nth("November") DEC new Month("December )i public static final Month[] month = t JAN, FEB, MAR, APR, MAY, JUN, 第10页共47页 www.wgqqh.com/shhgs/tij.html
Thinking in Java 3 rd Edition www.wgqqh.com/shhgs/tij.html email:shhgs@sohu.com ✄ 10 ☎ ✆ 47 ☎ //: c08:Months.java // Using interfaces to create groups of constants. package c08; public interface Months { int JANUARY = 1, FEBRUARY = 2, MARCH = 3, APRIL = 4, MAY = 5, JUNE = 6, JULY = 7, AUGUST = 8, SEPTEMBER = 9, OCTOBER = 10, NOVEMBER = 11, DECEMBER = 12; } ///:~ ¹3Java (áâòèc«¾ó(ôõñ3×ö ÷øË(Ñ×H³ )Q?·Û]}f`( static finalÛ interface public ¡ÝE}¥ù¨( package Y¦ import c08. * 3 c08. M on th s PAú]Q ¦;F × package (½¶ M on th s. JAN UARY u(?û´Qç Ì·Û, ¡g( 3× in tæòAm} C+ + ( en um Y¦(hüc (· ()C%8ÒFâ%˶c¾%V( µ·v çÍýþc¾Ï³çK(¯·U) ÄÅ¡Ìñî%½(hücÝE} ¦123×L ✝ ✞ ✞ ✟ //: c08:Month.java // A more robust enumeration system. package c08; import com.bruceeckel.simpletest.*; public final class Month { private static Test monitor = new Test(); private String name; private Month(String nm) { name = nm; } public String toString() { return name; } public static final Month JAN = new Month("January"), FEB = new Month("February"), MAR = new Month("March"), APR = new Month("April"), MAY = new Month("May"), JUN = new Month("June"), JUL = new Month("July"), AUG = new Month("August"), SEP = new Month("September"), OCT = new Month("October"), NOV = new Month("November"), DEC = new Month("December"); public static final Month[] month = { JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };