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ñí(¡º<gin terface X<3:!( =>?í@´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