致读者 我从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.wgqgh.com/shags/tii.htm 如果你觉得好,请给告诉我,你的鼓励是我工作的动力;如果你觉得不好,那 就更应该告诉我了,我会参考你的意见作修改的。我希望能通过这种方法,译 出一本配得上原著的书。 2003年9月8日 第1页共42页
shhgs@wgqqh.com 1 ✁ ✂ 42 ✁ 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
4:初始化与清理 随着计算杋革命的进步,“不安全”的编程方式已经成为让编程变得如此 昂贵的主要原因了。 这类安全性问题包括初始化( initialization)和清理( cleanup)这两项。C 程序的很多buq都是由程序员忘了对变量进行初始化引起的。碰到一些 用户不知道该如何初始化,甚至不知道要进行初始化的类库时,情况就更 是这样了。清理是一个特殊的问题,因为变量用过之后就没用了,因此会 很容易把这一步给忘了。这样程序仍然保留着那些元素所占用的资源,因 此资源会很快被耗尽(最常见的就是内存)。 C++引入了构造函数( constructor)的概念,这是一种能在对象创建的时 候自动调用的方法。Java也采纳了这种做法,此外对于那些无需再用的 对象,它还有一个会自动释放其所占内存的垃圾回收器。本章探讨了初始 化和清理问题,并且讲解了Java是如何处理这两个问题的 用构造函数确保初始化 可以这样认为,每个类都有一个名为 initialize()的方法。这个名字就 暗示了它得在对象使用之前调用。不幸的是,这么做的话,用户就得记住 要调用这个方法。Java类库的设计者们可以通过提供一种被成为构造函 数( constructor)的特殊方法,来保证每个对象都能得到初始化。如果类 有构造函数,那么Java就会在对象刚刚创建,用户还来不及得到的时 候,自动调用那个构造函数。这样初始化就有保障了 接下来的问题是如何命名这个方法。这有两层意思。第一,名字不能与类 的成员的名字相冲突。第二,由于构造函数是由编译器调用的,因此编译 器必须要能知道该调用哪个方法。既然C++的解决方案既简单又合理, 那么Java就沿用了这种做法:构造函数的名字就是类的名字。于是初始 化的时候这个方法的自动调用就变得顺理成章了。 下面是一个带构造函数的简单的类 //: c04: SimpleConstructor java / Demonstration of a simple constructor import com. bruceeckel. simpletest *i class Rock Rock((// This is the constructor System. out. println ("Creating Rock") public class SimpleConstructor t static Test monitor new Test ( public static void main(String[] args) i 第2页共42页
shhgs@wgqqh.com 2 ✁ ✂ 42 ✁ 4: ¸.(ÍXcÏ(áâµ´ôõÇáâÄò (%åæ, c !"#$f%(initialization)&¢(cleanup) exC â'(V b u g Æ(â')*,¥+,f%-9(.g3Ì /X01wÄf%23X01%,f%(45 ¦,&¢3×67(!"æ+^u,æòº RSP 3¬*, ¦â'89:;.YÌ(?@æ ò?@ºABCD(b· (EF) C++-t,GÚHI(constructor)(ÖJ 3;F¥KLM( Mý N(µJava [OP, Tò½¥)YÌÜîÁ( ¥KAm3׺ý Qk§D>EF(RSTUV ûWX,f %&¢!"Y©£, Java ÄZ¢ e×!"( ÝE ¦Ù[×Æm3×Ñ initialize( )(µ ×Ñ\ ]^,AF¥KçuNX_( ZT(/`a %N ×µJava 4(bcÝE^de3BGÚH I(constructor)(67µQ:f[×¥KÆ;gf%ÄÅ mGÚHIYZ Java ºF¥KggLM/QXhg( Mý NY×GÚHI ¦f%m:i, jkQ(!"ÄÑ ×µ mel¹m3Ñ\X; ()(Ñ\>no()GÚHI(áVN(æòá Vpq%;01wNr×µs9 C++(£Nµtsuvüw¢ YZ Java x, TyGÚHI(Ñ\(Ñ\)f %(M ×µ(ý Nz¢û, k¶3×{GÚHI(uv(y //: c04:SimpleConstructor.java // Demonstration of a simple constructor. import com.bruceeckel.simpletest.*; class Rock { Rock() { // This is the constructor System.out.println("Creating Rock"); } } public class SimpleConstructor { static Test monitor = new Test(); public static void main(String[] args) {
for (int i=0; i< 10: 1++) new Rock()i monitor. expect(new String[] i Creating Rock "Creating Rock "Creating Rock" "Creating Rock", "Creating Rock" Creating Rock", "Creating Rock Creating Rock }///:~ 现在,创建对象的时候 new Rock (i 不但要分配内存而且还要调用构造函数。这个过程是有保障的。因此,在 你能得到这个对象之前,它就已经被妥善地初始化了。 注意,编程风格要求的方法的首字母要小写的要求不适用与构造函数,因 为构造函数的名字必须与类的名字完全相同。 与其他方法一样,构造函数也可以有参数,这样你就能告诉它该如何进行 初始化了。前面这段程序经过简单地修改之后,也能让它的构造函数接受 参数 //: c04: SimpleConstructor2 java / Constructors can have arguments import com. bruceeckel simpletest*i class Rock2 I Rock2(int i)I System. out. println ("Creating Rock number " i public class simpleConstructor2 static Test monitor new Test ( public static void main(String[] args) i for (int i=0: i< 10: 1++) new Rock2(i) monitor.expect (new String[] i Creating Rock number 0", "Creating Rock number 1" Creating Rock number 2 "Creating Rock number 3 第3页共42页
shhgs@wgqqh.com 3 ✁ ✂ 42 ✁ for(int i = 0; i §Gµ3¦GÚHI[ÝEmI ¦¡;#AwÄ, f%,¶ â'õ^uvrïðu[;ÇA(GÚHIj Iy //: c04:SimpleConstructor2.java // Constructors can have arguments. import com.bruceeckel.simpletest.*; class Rock2 { Rock2(int i) { System.out.println("Creating Rock number " + i); } } public class SimpleConstructor2 { static Test monitor = new Test(); public static void main(String[] args) { for(int i = 0; i < 10; i++) new Rock2(i); monitor.expect(new String[] { "Creating Rock number 0", "Creating Rock number 1", "Creating Rock number 2", "Creating Rock number 3",
"Creating Rock number 4" Creating Rock number 5", "Creating Rock number 6 ", "Creating Rock number 7" Creating Rock number 8 Creating Rock number 9 }///: 构造函数的参数是一种能让你对对象的初始化提供参数的方法。比方说, Tree类有一个拿整数作参数的构造函数,而这个整数又表示树的高度, 那么你就可以这样来创建一个Tree对象: Tree t new Tree(12): // 12-foot tree 如果Tree(int)是类仅有的构造函数,那么编译器不会让你再用其它方 法创建Tree对象了。 构造函数解决了一大堆问题,提高了代码的可读性。比如,在上述的代码 中,根本用不着去调用像 initialize()这种,在概念上同对象的创建相 分离的方法。Java的对象创建和初始化是同一个概念—你不能要这个 而不要那个。 构造函数是一种特殊的方法,它没有返回值。这一点同void型的方法有 着本质上的区别,void型的方法什么都不返回,但这是你决定的,你也 可以让它返回些什么。而构造函数则什么都不返回,而且你别无选择 (new表达式确实会返回这个新创建的对象的 reference,但是构造函数 本身不返回任何值)。如果构造函数能有返回值,而且你还可以选择这个 值,那么编译器就要问了,它应该怎样处置这个返回值 方法的重载 名字管理是编程语言的一项重要特性。创建对象的时候,你会给内存空间 起名字。而方法是动作的名字。通过使用名字,别人就能更容易地理解和 修改程序了。这就像是在写散文——其目的就是要与读者交流 你用名字来表示对象和方法。不管是对你还是别人,好的名字能让代码读 起来更简单。 但是在把人类语言映射到编程语言的时候,会碰到了一件麻烦事。同一个 单词经常可以表达很多不同的意思——也就是说这个词被重载( overload) 了。碰到这些意思只有微不足道的差别的时候,这种情况就更常见了。你 会说“洗衬衫”,“洗车”,或者“给狗洗澡”。但是,如果你为了要让 第4页共42页
shhgs@wgqqh.com 4 ✁ ✂ 42 ✁ "Creating Rock number 4", "Creating Rock number 5", "Creating Rock number 6", "Creating Rock number 7", "Creating Rock number 8", "Creating Rock number 9" }); } } ///:~ GÚHI(I3;Ç¡¥¥K(f%deI(µ8µ$ Tree m3פI1I(GÚHIà פIü^(z YZ¡ÝE ¦QLM3× Tree ¥Ky Tree t = new Tree(12); // 12-foot tree ÄÅ Tree(int) m(GÚHIYZáVXºÇ¡Á§Aµ LM Tree ¥K, GÚHI£N,3Â!"d,(Ý 8ÄFJ( * X.N} initialize( ) FÖJJ¥K(LM> (µJava (¥KLMf%3×ÖJ¡X;% × àX%Y× GÚHI367(µAmT 3C void (µm . J(void (µZÆXT ¡NO(¡[ ÝEÇATÌZàGÚHIZÆXTàY¡Ü (new ´ñºT ×LM(¥K( referen ceGÚHI pXT)ÄÅGÚHI;mTàY¡ÝE × YZáV%!,AvwÕ¦Z ×T Ñ\ ¢áâ(3x%6 LM¥K(M¡º¬EF¡4 9Ñ\ൠ1(Ñ\^çÑ\ª;RSr¢£ ïðâ', }F«¢ §£(%¤¥ ¡Ñ\Q^¥KµX ¥¡ª(Ñ\;Ç 9Quv FPª¦§gáâ(Mº.g,3¨©ª3× v³õ·ÝEVX(¹m[$ ׳B«(overload) ,.g ̹móm¬X1(B(M 5· ,¡ º$Í®¯°ÏÍ®±Ï²Í¬³®´ÏÄÅ¡,%Ç