Thinking in Java 3rd Edition
第 1 页 共 23 页 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
致读者,
我从2002年7月开始翻译这本书,当时还是第二版。但是翻完前言和介绍部分后,chinapub就登出广告,说要出版侯捷的译本。于是我中止了翻译,等着侯先生的作品。
我是第一时间买的 这本书,但是我失望了。比起第一版,我终于能看懂这本书了,但是相比我的预期,它还是差一点。所以当Bruce Eckel在他的网站上公开本书的第三版的时候,我决定把它翻译出来。
说说容易,做做难。一本1000多页的书不是那么容易翻的。期间我也曾打过退堂鼓,但最终还是全部翻译出来了。从今年的两月初起,到7月底,我几乎放弃了所有的业余时间,全身心地投入本书的翻译之中。应该说,这项工作的难度超出了我的想像。
首先,g16847一本书和翻译一本书完全是两g11733g1119。g14533g16833g994中g7003是两g12193不g2528的g16833言,
g11004g14533g16833说g5483g5468g11033的g2489g4388,翻g6116中g7003之后就完全g11784了相。有时我g5483g14469g3921几分g19059,
g11004中g7003g18337g17860一g2489我能g11004几g12198g19059g16847懂的g2489g4388。g7368g1321g1929作g1038g16847g13785,一两g2489g16817g8821g6642
懂,g5194不g5445g2721g1332g10714g16311g6984本书,但g4557译g13785来说,这就不一g7691了。
g1866g8437,这是一本g16774g14533g16833的g1166g1901g13485g16774g14533g16833的g1166的书,所以g2528g5468多要g10043g20050g19762g14533g16833g16847
g13785的g6228g7427g7003g7735不g2528,它在g11004g16801,g2489g5347g7053g19766g19762g5132g19555g5859。g14533g16833g16847g13785g1262g5468g8439g17187这一点,但是g4557g3818g3281g16847g13785来说,这就是g17139g6297了。
g1889有,Bruce Eckel这g7691的g3835g10287g1166,g1901了1000多页,g3926g7536g18129g16765g1332g16847懂,他g4694不是
g3838g8821g19766g4388g731所以,书g18336还有一g1135g5468有g256g12121g5859g257的g2489g4388。比g3926那g2489g14891g2529的g256The
genesis of the computer revolution was in a machine,The genesis of our
programming languages thus tends to look like that machine.g257我就一g11464g8821g2519g1946该g5602
么翻译。我想g3835g8022g8821g1166能g2519g1946,说不定Bruce要的就是这g1022g6940g7536。
这是一本公g16760的g2529g14891,作g13785在g6228g7427上的g17908g16823g7092g2499g6373g2088。g13792作g1038译g13785,我的g13546g12255
能g2159差了g5468多。g1889g2164上上g19766g16774的这g1135g2419g3252,g1363g5483我不g5483不g7696g3818的g16892g5922。当我g18337
g16847初g12307的时候,我g2469g10628g19668要g1474g6925的地g7053g4466在g3838多了。g3252g8504,我不能g10628在就公开全部译g12307,我g2494能公开g5062g13475g1474g6925过的部分。不过这不是最终的版本,我还g1262g13499
g13505g1474g16758的。
本来,我g1946g3803到10月g1233,等我g1474g6925完前7g12468之后g1889公开。但是,我g2469g10628我g2460有点要放弃了,g3252g8504我决定g13485g14270己一点压g2159,g10628在就公开。以后,我将g1474g6925完一
g12468就公开一g12468,请关注www.wgqqh.com/shhgs/tij.html。
g3926g7536g1332觉g5483g3921,请g13485告诉我,g1332的鼓励是我工作的动g2159;g3926g7536g1332觉g5483不g3921,那就g7368应该告诉我了,我g1262参考g1332的g5859见作g1474g6925的。我希望能通过这g12193g7053法,译出一本配g5483上g2419g14891的书。
shhgs
2003年9月8日
Chapter 5,Hiding the Implementation
第 2 页 共 23 页 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
5,隐藏实现
在g19766向g4557象的设计中,最关键的问题就是g256将g1262变和不g1262变的东西分离开来。g257
这一点g4557类库尤g1038g18337要。类库的g1363g11004g13785(客户g12255序员)应该能完全仰赖类库,他们知道,即g1363类库出了新版本,他们也不必g18337g1901代g11733。另一g7053g19766,
类库的创建g13785也应该g2499以在确保不g5445g2721客户g12255序员代g11733的前提下,保留g4557
类库作g1474正和g6925进的权利。
要达到上g17860目的,g2499以g1363g11004约定。比g7053说,类库的开g2469g1166员必须遵守:g1474
g6925类的时候不删除g10628有的g7053法,g3252g1038这g2499能g1262g5445g2721客户g12255序员的代g11733。但是还有一g1135g7368棘手的问题。就拿g6116员数据来说,类库的开g2469g1166员g2460g5602么知道客户g12255序员g1262g1363g11004哪g1135数据呢g731g4557于那g1135g2494g994类的内部g4466g10628有关的,不应该g16765客户g12255序员g1363g11004的g7053法来说,情g1929也一g7691。但是,g3926g7536类库的开g2469
g1166员想g11004一g12193新的g4466g10628来替换旧的,那他g2460该g5602么做呢g731g4557类的任g1321g1474g6925
g18129g2499能g1262g11784坏客户g12255序员的代g11733。这g7691,类库的开g2469g1166员就被套上了紧箍咒,什么g18129不能g6925了。
g1038了g16311决这g1022问题,Java提供了访问控制符(access specifier),这g7691类库的开g2469g1166员能告诉客户g12255序员,他们能g11004什么,不能g11004什么了。访问控制权限从松到紧依g8437是public,protected,package权限(也就是不
g13485任g1321关键g16801),以及private。g16847了上g19766那段,g1332g2499能g1262g16760g1038,作g1038类库的设计g13785,g1332应该尽g2499能的把所有东西g18129做g6116g256privateg257的,g5194且g2494
公开g1332想g16765客户g12255序员g1363g11004的g7053法。完全正确!尽管g4557于那g1135g11004g1866它g16833言
(特别是C)g13546g12255,g5194且g5062g13475习惯了不受限制地访问任g1321东西的g1166来说,这么做通g5132是有违g5132g10714的。g16847过本g12468之后,g1332就g1262g4557Java的访问控制g7368有信心了。
但是,什么是组件类库(library of component)以及g5602g7691去控制g256谁能访问类库中组件g257的问题还g8821有完全g16311决。还有一g1022问题,就是组件是g5602
g7691被捆绑g6116一g1022联系紧密的类库单元的。这是由Java的package关键
g16801控制的,g8504g3818类是不是属于g2528一g1022package,还g1262g4557访问控制符产生
g5445g2721。所以,我们将从g5602g7691将类库组件(library components)放入
packageg18336入手,开始本g12468的学习。接下来,g1332就能完全g10714g16311访问控制符的g5859思了。
package,类库的单元
当g1332g1363g11004import关键g16801引入一g1022完g6984的类库的时候,这g1022package就能g1038g1332所g11004了,例g3926
import java.util.*;
Thinking in Java 3rd Edition
第 3 页 共 23 页 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
g1262把Javag7643g1946版g18336的工g1867类库(utility library)全g18129引进来。比g3926,
java.utilg18336g19766有一g1022ArrayList类,g3252g8504g1332g7094g2499以g11004全g2529
java.util.ArrayList(这g7691就g11004不着importg16833g2489了),也g2499以g11464接g1901
ArrayList了(g3252g1038g5062g13475有了import)。
g3926g7536g1332g2494想引入一g1022类,那g1332g2499以在importg16833g2489g18336g19766g6363g2529道g4007地引g11004
类了。
import java.util.ArrayList;
g10628在g1332就g2499以g11464接g1363g11004ArrayListg13792不g11004g9167g2164任g1321限定g16801了。但是
java.utilg18336g19766的g1866它的类就不能g11004了。
之所以要g1363g11004import,是g3252g1038它提供了一g12193管g10714g2529g4395g12366间(name
spaces)的g7438制。类的所有g6116员的g2529g4395g18129是相g1126g10432g12447的。A类g18336g19766的f( )
g7053法不g1262g2528B类g18336g19766,有着相g2528g256g16855g11004特g5461(signiture,即参数g2027g15932)g257
的f( )相g1926g12373。但是类的g2529g4395呢g731g1563设g1332创建了一g1022Stack类,g5194且把它g16025到一g2500g5062g13475有了一g1022别g1166g1901的Stack类的g7438g3132上,那g2460g1262g2469生什么
g1119呢g731Java之所以要g4557g2529g4395g12366间g6329有完全的控制,就是要g16311决这g12193g9520在的g2529g4395g1926g12373,g5194且能不受Internet的g7475g13550,创建出完全g2819一的g2529g4395。
到目前g1038止,本书所g1042的g18129是单g7003件的例g4388,g13792且g18129是在本地g17828g15904的,g3252
g8504g8821必要g1363g11004package。(在这g12193情g1929下,类的g2529g4395是放在g256default
packageg257的g2529下的。) 当g9994这也是一g12193做法,g13792且g1038了g12628单起见,本书的g1866余g12468g14422也尽g2499能g1363g11004这g12193g7053法。但是,g3926g7536g1332打g12651创建一g1022,能g2528g7438
g3132上g1866它Javag12255序相g1126g1872容的类库g6122g12255序,g1332就g5483考g15397一下g3926g1321g18003g1825g2529
g4395g1926g12373了。
Java的g9316代g11733g7003件通g5132被g12228g1038g13546译单元(compilation unit有时也g12228翻译单元translation unit)。g8611g1022g13546译单元g18129必须是一g1022以,javag13479g4626的
g7003件,g13792且g1866中必须有一g1022g994g7003件g2529相g2528的public类 (g3835g4579g1901也必须相
g2528,但是不g2265g6336,java的g7003件g6205g4649g2529)。g8611g1022g13546译单元g2494能有一g1022
public类,g2554g2029g13546译g3132就g1262g6265g19181。g3926g7536g13546译单元g18336g19766还有别的类,那么这g1135类就g6116了这g1022g1039要的public的类的g256g17753g2173g257类了,这是g3252g1038它们g18129
不是public的,g3252g8504g4557g3818g19766g1002g11040来说它们g18129是看不到的。
g13546译.javag7003件的时候,它g18336g19766的g8611g1022类g18129g1262产生g17767出。g1866g17767出g7003件的g2529
g4395就是.javag7003件g18336的类的g2529g4395,但是g1866g6205g4649g2529是.class。这g7691,g1901不了几g1022.javag7003件就g1262产生一g3835g3546.classg7003件。g3926g7536g1332有过g11004g13546译g16833言g13546
g12255的g13475g20576,那么g1332g2499能g1262g4557这g1022过g12255g5875到习以g1038g5132了:先g11004g13546译g3132生g6116一
Chapter 5,Hiding the Implementation
第 4 页 共 23 页 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
g3835g3546中间g7003件(通g5132是g256objg257g7003件),g9994后g1889g11004linker(创建g2499g6203g15904g7003件)
g6122librarian(创建类库)把这g1135中间g7003件g4565g16025起来。但是,Java不是这g7691
工作的。一g1022能正g5132工作的g12255序就是一g3835g3546.classg7003件,当g9994也g2499以(g11004
Java的jar工g1867)把它们g4565g16025和压g13565g6116Java ARchive (JAR)g7003件。
Javag16311g18334g3132g1262g17139g17143g4559g6226,g16025g17745和g16311g18334[26]这g1135g7003件的。
类库就是一组类g7003件。g8611g1022g7003件g18129有一g1022public类 (不是一定要有
public类,但通g5132g18129是这g7691),g3252g8504g8611g1022g7003件g18129代g15932着一g1022组件。g3926g7536g1332
想把这g1135组件(g18129在它们g14270己的那g1022.java和.classg7003件g18336)g18129组g13467起来,那就应该g11004package关键g16801了。
当g1332把,
package mypackage;
放到g7003件开g3848的时候 (g3926g7536要g11004package,那么它必须是这g1022g7003件的第一g1022g19762注g18334的g15904),g1332就g3780g7138了,这g1022g13546译单元是mypackage类库的组g6116部分。g6122g13785换一g12193说法,g1332要g15932达的g5859思是,这g1022g13546译单元的
public类的g2529g4395是在mypackage的g2529g4395之下的(under the
umbrella of the name mypackage),任g1321想g1363g11004这g1022类的g1166必须g1363
g11004它的全g2529,g6122g13785g11004import关键g16801把mypackage引进来(g11004前g19766g16774
的g2162法)。注g5859Java的约定是g11004全g4579g1901来g15932g12046package的g2529g4395,中间单
g16801也不例g3818。
g1042例来说,g1563设这g1022g7003件的g2529g4395是MyClass.java。于是g7003件g18336g19766g2499以有,g13792且g2494能有一g1022public类,g13792这g1022类的g2529g4395g2494能是MyClass (g3835
g4579g1901g18129要相g2528),
package mypackage;
public class MyClass {
//,,,
g10628在g3926g7536有g1166想要g11004MyClass,g6122g13785mypackageg18336g19766的g1866它
public类,那他就必须g1363g11004import关键g16801来引入mypackage下的
g2529g4395了。还有一g1022g2162法,就是g13485出这g1022类的全g2529,
mypackage.MyClass m = new mypackage.MyClass();
g11004importg2499以g16765代g11733g7186g5483g7368g9177g7982一点,
import mypackage.*;
Thinking in Java 3rd Edition
第 5 页 共 23 页 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
//,,,
MyClass m = new MyClass();
作g1038类库的设计g13785,g1332g5483g16772g1315,package和import这两g1022关键g16801的作
g11004是要把一g1022单g10432的全g4628g2529g4395g12366间分g2118开来,这g7691不g16782Internet上有多
g4581g1166在g11004Javag13546g12255,g1332就g18129不g1262g11908到g2529g4395g1926g12373的问题了。
创建独一无二的package名字
g2499能g1332也g2469g10628了,由于packageg8821有被g11507的g256g4565g16025g257g6116一g1022单g10432的g7003
件,g13792packageg2460是由g5468多,classg7003件组g6116的,g3252g8504g1119情就有点g1093
了。要g16311决这g1022问题,g17751g1038g7138g7246的做法是把所有g2528属一g1022g2265的,classg7003
件g18129放到一g1022目g5417g18336;也就是利g11004g6817作系g13491的g4630g8437g7003件g13479g7512来g16311决这g1022问题。这是Javag16311决这g1022问题的g7053法之一;后g19766要介绍的jarg12255序是另一
g1022g16311决g2162法。
将package的g7003件g6922进一g1022单g10432的g4388目g5417g18336还g16311决了另g3818两g1022问题:创建g10432一g7092二的packageg2529g4395,以及g5122g2173Java在g3809g7446的目g5417g13479g7512中g6226到它们。我们g5062g13475在第2g12468g16774过了,这是通过将,classg7003件的g17347g5464信g5699放到package的g2529g4395g18336g19766来完g6116的。Java的约定是packageg2529g4395的第一部分应该是类的创建g13785的Internetg3507g2529的g2465g1901。由于Internetg3507g2529的
g2819一g5627是有保g16789的,g3252g8504g2494要g1332遵守这g1022约定,package的g2529g4395就g13955定是g2819一的,这g7691就不g1262有g2529g4395g1926g12373的问题了。(除g19762g1332把g3507g2529g16765g13485了别
g1166,g13792他g2460g11004g2528一g1022g3507g2529来g1901Javag12255序。)当g9994,g3926g7536g1332还g8821有注g1888g3507
g2529,那g1332完全g2499以g13546一g1022(比g3926g11004g1332的g4007和g2529),g9994后g11004它来创建
package的g2529g4395。g3926g7536g1332打g12651要g2469g5079Javag12255序,那么还是应该g12257g5506g14469点
g12946g2159去g6642g1022g3507g2529。
这g1022g6228g5051的第二部分是把package的g2529g4395g7156g4568到本地g7438g3132的目g5417,这g7691
当g1332g2563动Javag12255序,g19668要g16025g17745,classg7003件的时候 (当g12255序g19668要创建g7588
g1022类的g4557象,g6122g13785第一g8437访问那g1022类的staticg6116员的时候,它g1262动g5589g6203
g15904这g1022过g12255的),它就知道该在哪g1022目g5417g4559g6226这g1022,classg7003件了。
Javag16311g18334g3132是这g7691工作的。首先,它要g6226到CLASSPATH[27]g10627g3671变g18339
(这是通过g6817作系g13491设g13634的,有时Javag4445g16025g12255序g6122g13785Java工g1867的g4445g16025g12255
序g1262g1038g1332设g13634)。 CLASSPATHg2265g2559了一g1022g6122多g1022目g5417,这g1135目g5417g1262被当作g7693目g5417供Javag6640g13046.classg7003件。从这g1022g7693目g5417出g2469,g16311g18334g3132g1262将
packageg2529g4395g18336的g8611g1022点g18129换g6116斜杠 (g3252g8504,g7693据g6817作系g13491的不g2528,
package foo.bar.baz就被转换g6116foo\bar\bazg6122
foo/bar/baz,g6122g13785g1866它g2499能的形g5347),这g7691它生g6116了以CLASSPATH
g1038g7693的相g4557g17347g5464。g9994后这g1135g17347g5464g1889g994CLASSPATHg18336的各条g16772g5417相连。
Chapter 5,Hiding the Implementation
第 6 页 共 23 页 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
这才是Javag11004package的g2529g4395g4559g6226.classg7003件的地g7053。(g8504g3818,它还
g1262g7693据Javag16311g18334g3132所在的位g13634查g6226一g1135g7643g1946目g5417。)
g1038了能g16774g5483g7368g9177g7982,就拿我的g3507g2529bruceeckel.comg1042例。它倒过来就是com.bruceeckel,这g7691我g1901的类就有了全球g2819一的g2529g4395了。(过去,com,edu,org这g1135g6205g4649,在Java的packageg2529g4395g18336g19766是要g3835
g1901的,但是Java 2作了g6925进,所以g10628在package的g2529g4395g18129是g4579g1901的。)
我还g2499以进一步分下去,创建一g1022g2529g1038simple的类库,所以package
的g2529g4395是,
package com.bruceeckel.simple;
g10628在,g1332就能g11004这g1022package的g2529g4395来管下g19766这两g1022g7003件了,
//,com:bruceeckel:simple:Vector.java
// Creating a package,
package com.bruceeckel.simple;
public class Vector {
public Vector() {
System.out.println("com.bruceeckel.simple.Vector");
}
} ///:~
等到g1332要g14270己g1901package的时候,g1332就g1262g2469g10628,packageg16833g2489必须是
g7003件g18336的第一g1022g19762注g18334g15904。第二g1022g7003件看上去g19762g5132相似,
//,com:bruceeckel:simple:List.java
// Creating a package,
package com.bruceeckel.simple;
public class List {
public List() {
System.out.println("com.bruceeckel.simple.List");
}
} ///:~
在我的g7438g3132上这两g1022g7003件g18129放在这g1022g4388目g5417g18336,
C:\DOC\JavaT\com\bruceeckel\simple
Thinking in Java 3rd Edition
第 7 页 共 23 页 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
g2494要看一遍这g1022g17347g5464,g1332就g1262g2469g10628package的g2529g4395
com.bruceeckel.simple,但是这g1022g17347g5464的前g19766部分g2460是什么呢g731这是由CLASSPATHg10627g3671变g18339控制的,在我的g7438g3132上,它是,
CLASSPATH=.;D:\JAVA\LIB;C:\DOC\JavaT
g1332g1262看到CLASSPATHg2499以有g3921几g1022g2499供选择的g6640g13046g17347g5464。
但是,g1363g11004JARg7003件的时候g1262有一点变化。除了要告诉它该到哪g18336去g6226
这g1022JARg7003件,g1332必须将g7003件g2529放到CLASSPATHg18336g19766。所以g4557g2529g1038
grape.jar的JAR来说,CLASSPATH应该g2265g6336,
CLASSPATH=.;D:\JAVA\LIB;C:\flavors\grape.jar
设完CLASSPATH之后,下g19766这g1022g7003件就g2499以放在任g1321目g5417g18336了,
//,c05:LibTest.java
// Uses the library,
import com.bruceeckel.simpletest.*;
import com.bruceeckel.simple.*;
public class LibTest {
static Test monitor = new Test();
public static void main(String[] args) {
Vector v = new Vector();
List l = new List();
monitor.expect(new String[] {
"com.bruceeckel.simple.Vector",
"com.bruceeckel.simple.List"
});
}
} ///:~
当g13546译g3132g11908到了simple类库的importg16833g2489的时候,它就开始在
CLASSPATH所g13485出的目g5417下g6640g13046,先g6226com\bruceeckel\simpleg4388
目g5417,g1889g6226g13546译后的g7003件(Vector就g6226Vector.class,List 就g6226
List.class)。注g5859Vector和List类,以及g1866中要g11004的g7053法g18129必须是
public的。
g4557Java的初学g13785来说,设g13634CLASSPATH曾g13475是一桩g19762g5132棘手的g1119(至
g4581我开始的时候是这g7691的),所以Sun在Java 2的JDKg18336g19766作了一g1135g6925
进,g16765它变g5483g12257g5506g7246能一g1135。g1332g1262g2469觉g4445g16025之后,即g1363不设g13634
CLASSPATH,它也能g13546译和g17828g15904一g1135基本的Javag12255序。g9994g13792要g13546译和
Chapter 5,Hiding the Implementation
第 8 页 共 23 页 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
g17828g15904本书的g9316代g11733(g2499以从www.BruceEckel.com下g17745),g1332就必须将这
g1135代g11733的g7693目g5417g2164到CLASSPATHg18336g19766。
冲突
g3926g7536两g1022g256*g257所引入的类库g18129g2265g6336一g1022g2528g2529的类,那g2460g1262g5602g7691呢g731g1042例来说,g1563设有g1022g12255序,
import com.bruceeckel.simple.*;
import java.util.*;
由于java.util.* 也g2265g6336了一g1022Vector类,g3252g8504这就有g2499能g1262引g2469g1926
g12373。g9994g13792,g2494要g1332不g1901g1262引起g1926g12373的代g11733,一切g1262OK——这g12193做法g5468
g3921,g3252g1038不g9994的g16817,g1332g5483g1038了g18003g1825g7693本不g2499能g2469生的g1926g12373g13792多g1901g5468多代
g11733。
但是g3926g7536g1332要创建一g1022Vector的g16817,g1926g12373就g11507的g1262来了,
Vector v = new Vector();
g1332g6363的是那g1022Vector类呢g731g13546译g3132不知道,g16847代g11733的g1166也不知道。所以
g13546译g3132就g6265g19181了,它g1262要g1332g7138确地g6363g7138这是哪g1022类。比g7053说,g3926g7536我要g1363
g11004Javag7643g1946的Vector,我就必须说,
java.util.Vector v = new java.util.Vector();
由于这g12193g1901法(g1889g2164上CLASSPATH)g5062g13475能完全g6363g7138Vector的位g13634
了,g3252g8504除g19762g1332还要g1363g11004java.util的g1866它类,g2554g2029就不必g1889g1363g11004
import java.util.*。
一个自定义的工具类库
有了这g1135知识,g1332就能创建g1332g14270己的工g1867类库以减g4581甚至彻底消除g18337g3809代
g11733了。g1563设我们要g1038System.out.println( ) 创建一g1022别g2529以减g4581打
g4395的g18339。这g2499以是tools package的一部分,
//,com:bruceeckel:tools:P.java
// The P.rint & P.rintln shorthand,
package com.bruceeckel.tools;
public class P {
public static void rint(String s) {
Thinking in Java 3rd Edition
第 9 页 共 23 页 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
System.out.print(s);
}
public static void rintln(String s) {
System.out.println(s);
}
} ///:~
这g12193g12628g1901形g5347g7094能以g2164换g15904符的形g5347(P.rintln()),也能以不g2164换g15904符的形g5347(P.rint())打印String。
g1332能猜到,这g1022g7003件一定是位于CLASSPATH的g7588g1022目g5417的
com/bruceeckel/toolsg4388目g5417下。g13546译之后,g1332就能在系g13491的任g1321
地g7053g11004importg16833g2489引入P.classg7003件了,
//,c05:ToolTest.java
// Uses the tools library,
import com.bruceeckel.tools.*;
import com.bruceeckel.simpletest.*;
public class ToolTest {
static Test monitor = new Test();
public static void main(String[] args) {
P.rintln("Available from now on!");
P.rintln("" + 100); // Force it to be a String
P.rintln("" + 100L);
P.rintln("" + 3.14159);
monitor.expect(new String[] {
"Available from now on!",
"100",
"100",
"3.14159"
});
}
} ///:~
注g5859,不g16782哪g12193g4557象,g2494要放进了Stringg15932达g5347,它就g1262被强制转化g1038
这g1022g4557象的Stringg15932g12046形g5347了;在上g17860g12255序中,把g12366的String放进g15932
达g5347就是g1038了达到这g1022目的。但是这却g16765我们注g5859到了一g1022有趣的g10628象。
g3926g7536g1332g11004System.out.println(100)的g7053g5347进g15904g16855g11004,那么它就不g1262
把参数转换g6116String了。g13475过一番特别的g18337g17745之后,g1332g2499以也g2499以g16765P
g1867g3803这g7691的功能(这是本g12468练习的要求)。
所以从g10628在开始,g2494要g1332g1901了什么新的,能派上g11004场的工g1867,g1332就g2499以把它g2164到g1332g14270己的toolsg6122util目g5417。
使用import来改变程序的行为方式
Chapter 5,Hiding the Implementation
第 10 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
Javag8821有g4466g10628C的g256条件g13546译(conditional compilation)g257。所谓条件
g13546译就是,不g11004g1474g6925g9316代g11733,g2494g11004一g1022开关就能g16765g12255序产生不g2528的g15904g1038g7053
g5347。Java之所以要g2088除这g1022特g5627,g2499能是g3252g1038它g1039要是g11004来g16311决C的跨平g2500的问题的:g12255序的不g2528部分g1262g7693据平g2500的不g2528g13792采g11004不g2528的g13546译g7053
g5347。由于Java的初衷就是要跨平g2500,g3252g8504这g12193特g5627就变g5483多余了。
但是条件g13546译还有一g1135别的g5468有价值的g11004途。最g5132见的就是g11004它来g16855试代
g11733。g16855试功能在开g2469版g18336是能g11004的,但在正g5347版g18336g2029被禁了。g1332g2499以通过
g1474g6925package来切换g16855试版和g2469g5079版所g1363g11004的代g11733,来达到上g17860目的。
这g12193g6228g5051能g11004于任g1321类型的g256有条件的代g11733(conditional code)g257。
使用package的忠告
值g5483注g5859的是,g8611g8437创建packageg13485它起g2529的时候,g1332也隐g2559地设g13634了一g1022目g5417g13479g7512。这g1022package必须保存在由它的g2529g4395所g6363g12046的目g5417g18336,
g13792这g1022目g5417g2460必须在CLASSPATH下g19766。刚开始做package的g4466g20576的时候,g2499能g1262g16765g1166觉g5483有g1135泄气,g3252g1038除g19762g1332严g7696遵守了package的g2529
g4395就是目g5417g17347g5464这一规g2029,g2554g2029即便这g1022类就呆在g2528一g1022目g5417g18336,g1332也g1262
g5483到一g3835串莫g2529g1866妙的,告诉g1332g6226不到这类的消g5699。g3926g7536g1332g5483到这g12193消
g5699,就先把packageg16833g2489注g18334掉,g3926g7536它能g17828g15904了,g1332就知道问题出在哪g18336了。
Java的访问控制符
g13546g12255的时候,public,protected以及private这三g1022Java访问控制符,应该放在类的g8611g1022g6116员的定义部分的前g19766,不管这g1022g6116员是数据还是g7053法。一g1022访问控制符g2494管它所定义的这一项。这g2528C++形g6116了鲜g7138
的g4557比。C++的访问控制符g1262一g11464管下去,g11464到出g10628另一g1022。
g8611g7691东西g18129g1262有一g1022访问控制符,不是这g1022就是那g1022。下g19766我们就从默g16760
的访问权限开始,学习各g12193访问控制符的权限。
package访问权限
g3926g7536像本g12468之前的g12255序那g7691,g7693本就不g13485访问控制符,那情g1929g2460g1262g3926g1321
呢g731默g16760的访问权限g8821有关键g16801,但通g5132还是把它g12228g1038package权限
(package access,有时也g12228g1038g256friendlyg257) 。它的g5859思是,所有g2528属这g1022package的类g18129能访问这g1022g6116员,但是g4557那g1135不属于这g1022package
的类来说,这g1022g6116员就是private的了。由于g13546译单元——也就是g9316g7003
件——g2494能属于一g1022package,g3252g8504g2528一g1022g13546译单元g18336的各g1022类,g14270动就能通过package权限进g15904相g1126访问了。
package权限能g16765g1332将相g1126关联的类组g13467g6116package,这g7691它们之间就能g5468g7053便地进g15904访问了。当g1332把类放到package的时候,也就是说赋予
Thinking in Java 3rd Edition
第 11 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
它的package权限的g6116员以相g1126访问的权利的时候,g1332就g256g6329有g257了这
g1022package的代g11733。g2494有g1332的g12255序才能g4557g1332的g1866它g12255序进g15904package
权限的访问,这是g5468合逻辑的。g2499以这么说,有了package权限,将类组g13467g6116package才变g5483有g5859义。在g5468多g16833言g18336,g1332g2499以g11004任g1321g7053g5347来组
g13467g7003件,但是Javag1262强制g1332g11004一g12193g7368合g10714的g7053g5347把它们组g13467起来。g8504
g3818,g1332还g2499能g1262要将一g1135不应该能访问当前package的类排除出去。
哪g1135代g11733g2499以访问类的g6116员,是由类g14270己控制的。g8821有什么能g256穿墙g13792
入g257的神奇g2162法。另一g1022package的代g11733不能说g256嗨,我是Bob的朋友g257,g9994后要求看Bob的protected的,package权限的,g6122g13785
private的g6116员。g3926g7536g1332想g16765别g1166能访问到这g1022g6116员,那g2819一g2162法就是,
1,把这g1022g6116员做g6116public的。这g7691任g1321g1166,任g1321地g7053就g18129能访问到它了。
2,不放任g1321访问控制符,赋予这g1022g6116员package权限,g9994后往
packageg18336g19766放g1866它类。这g7691,这g1022package的g1866它类就能访问这
g1022g6116员了。
3,我们g1262在第6g12468g16774g13499承。届时g1332g1262看到,g13499承类除了能访问父类的
publicg6116员之g3818,还g2499以访问g1866protectedg6116员(但是不能访问
privateg6116员)。g2494有当两g1022类g18129g2528属一g1022package的时候,它才能访问packageg6116员。不过g1332g10628在还不必g1038g8504g6817心。
4,提供g256访问g3132/g1474g6925g3132g257g7053法(accessor/mutatorg7053法,也被g12228g1038
g256get/setg257g7053法)。以OOP的观点衡g18339,这是最合g10714的做法,g13792且也是JavaBean的基础,我们g1262到第14g12468g1889g16774。
public:访问接口的权限
当g1332g1363g11004public关键g16801的时候,g1332的g5859思是:任g1321g1166,尤g1866是那g1135要g1363
g11004这g1022类库的客户g12255序员,g18129能访问那g1022紧跟在public后g19766g3780g7138的g6116
员。g1563设g1332定义了一g1022叫dessert的package,g1866中有下g19766这g1022g13546译单元,
//,c05:dessert:Cookie.java
// Creates a library,
package c05.dessert;
public class Cookie {
public Cookie() {
System.out.println("Cookie constructor");
}
void bite() { System.out.println("bite"); }
} ///:~
Chapter 5,Hiding the Implementation
第 12 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
g16772g1315,Cookie.java所生g6116的classg7003件必须保存在CLASSPATH项下
g7588g1022目g5417的c05g4388目g5417(g15932g12046本书的第5g12468)的dessertg4388目g5417下。千万不要想当g9994地g16760g1038Java总是g1262从当前的目g5417开始查g6226。g3926g7536g1332不把
‘.’放到CLASSPATH,Java是不g1262查g6226当前目g5417的。
g10628在,g3926g7536g1332g11004Cookie创建了一g1022g12255序,
//,c05:Dinner.java
// Uses the library,
import com.bruceeckel.simpletest.*;
import c05.dessert.*;
public class Dinner {
static Test monitor = new Test();
public Dinner() {
System.out.println("Dinner constructor");
}
public static void main(String[] args) {
Cookie x = new Cookie();
//! x.bite(); // Can't access
monitor.expect(new String[] {
"Cookie constructor"
});
}
} ///:~
由于Cookie的g7512g17908函数是public的,g5194且Cookie这g1022类也是
public的,g3252g8504g1332g2499以创建Cookieg4557象(我们过一g1262儿谈public类的g8022念。) 但是g1332不能在Dinner.javag18336g19766访问bite( ),这是g3252g1038它是package权限的,g2494能在desert 这g1022packageg18336g19766访问,g3252g8504g13546
译g3132g1262禁止g1332g1363g11004它。
默认的package
g6122许g1332g1262觉g5483g5468奇怪,下g19766这段代g11733g8821有遵守规g2029,g5602么也能g13546译通过,
//,c05:Cake.java
// Accesses a class in a separate compilation unit,
import com.bruceeckel.simpletest.*;
class Cake {
static Test monitor = new Test();
public static void main(String[] args) {
Pie x = new Pie();
x.f();
monitor.expect(new String[] {
"Pie.f()"
});
}
} ///:~
Thinking in Java 3rd Edition
第 13 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
这g1022目g5417g18336g19766还有一g1022g7003件,
//,c05:Pie.java
// The other class,
class Pie {
void f() { System.out.println("Pie.f()"); }
} ///:~
刚开始的时候,g1332g2499能g1262把它们视作两g1022完全不相关的g7003件,所以g1262奇怪
Cakeg5602么能创建Pieg4557象,g5194且g16855g11004它的f( )g7053法的!(注g5859,g1332必须把‘.’放到CLASSPATHg18336g19766,这g7691g7003件才能顺利地g13546译通过。)g2499能
g1332g1262g16760g1038Pie和f( )g18129是package访问权限的,g3252g8504Cake是不能访问的。它们的确g18129是package权限的——这点g8821g19181。之所以能在
Cake.javag18336g19766访问Pie,是g3252g1038这两g1022g7003件g18129在g2528一g1022目g5417g18336g19766,g5194
且g18129g8821有g7138确g6363g7138它是属于哪g1022package的。Javag1262g16760g1038这类g7003件是属于这g1022目g5417的g256默g16760packageg257的,g3252g8504g4557这g1022目g5417g18336边的g1866它g7003件来说,它们就g18129是package权限的了。
private:你碰都碰不到!
private关键g16801的g5859思是:除g19762是g11004这g1022类(g2265g2559这g1022g6116员的类)的g7053法,
g2554g2029一律不g5483访问。g2528一g1022packageg18336的g1866它类也不能访问privateg6116
员,所以这就有点像是在g256作茧g14270g13550g257。但是另一g7053g19766,一g1022package
g5468g2499能是由g3921几g1022g1166合作开g2469的,g3252g8504private能g16765g1332g7693据g14270己的g19668要
g1474g6925那g1135g6116员,g13792不g11004g6297心这么做g1262不g1262g4557别的类产生g5445g2721。
默g16760的package权限通g5132g5062g13475提供了一g12193g17751g1038合适的隐藏g6940g7536;g16772g1315,
从客户g12255序员的角度来看,package权限的g6116员也是不能访问的。这g7691
正g3921,g3252g1038默g16760的权限就是g1332g13475g5132要g11004的那g1022(g13792且还是g1332忘了设g13634的时候g1262g11004那g1022的)。于是通g5132情g1929下,g1332g2494要把那g1135要g4557客户g12255序员开放的
g6116员设g6116public就g15904了。g13479g16782是,g2499以先不考g15397g3835g18339地g1363g11004private,
g3252g1038即g1363不g11004,也还过g5483去。(这点g2528C++是截g9994不g2528。)但是,始终g3926
一地g1363g11004private还是g5468g18337要的,特别是遇到多线g12255的时候。(到第13
g12468就知道了。)
下g19766是一g1022g17828g11004private的例g4388,
//,c05:IceCream.java
// Demonstrates "private" keyword,
class Sundae {
Chapter 5,Hiding the Implementation
第 14 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
private Sundae() {}
static Sundae makeASundae() {
return new Sundae();
}
}
public class IceCream {
public static void main(String[] args) {
//! Sundae x = new Sundae();
Sundae x = Sundae.makeASundae();
}
} ///:~
这g18336演g12046了一g1022能g2469挥private的特长的例g4388:g1332g2499能要控制g4557象的创建,g5194且阻止别g1166g11464接访问g7588g1022g7512g17908函数(g6122g13785所有的g7512g17908函数)。在上g17860
例g12255中,g1332不能通过g7512g17908函数来创建Sundaeg4557象;相g2465g1332必须g16855g11004
makeASundae( )g7053法来创建。[28]
g2494有一g1022g7053法,当g1332把它做g6116private的时候g2499以一点心思g18129不g6297,这就是类的g256helperg257g7053法。这g7691就能保g16789,g1332不g1262一不g4579心就把这g1022g7053法
g11004到package的g1866它地g7053,从g13792g17908g6116g1332g14270己g18129不能g1474g6925g6122删除的尴尬了。g7053法设g6116private之后,这项权利就被保留下来了。
g4557类的private数据来说,情g1929也一g7691。除g19762g1332必须开放类的底g4630g4466g10628
(出g10628这g12193情g1929的g2499能g5627要比g1332相像的要g4581的多),g2554g2029就应该将所有的数据g18129设g6116private的。但是这g5194不是在说,g2494要类g18336有了一g1022g7588g1022g4557象的private的reference,那么g1866它g4557象就不能有这g1022g4557象的public
的reference了。(参见附g5417A的别g2529(aliasing)g12468g14422)
protected,继承的访问权限
要想弄懂protected访问权限,就g5483先g16774一点后g19766的东西。首先要告诉
g1332,在g16774g13499承(第6g12468)之前,即g1363g1332不g11004g10714g16311这部分内容也g2499以g13499g13505g16847下去。但是g1038了叙g17860的完g6984g5627,我们还是先g12628单地g16774一下,g1889g11004
protectedg1042一g1022例g4388。
protected关键g16801所处g10714的是一g12193被g12228g1038g13499承(inheritance)的g8022念,所谓g13499承就是选一g1022g10628g6116的类——我们g12228之g1038基类(base class)——g9994后在不g6925变g5062有类的前提下,往g18336g19766g9167g2164新的g6116员。g1332还g2499以g1474g6925g5062有类的g6116
员的g15904g1038g7053g5347。要g13499承一g1022g5062有的类,g1332必须说g7138新的类extends一g1022
g5062有的类,就像这g7691,
class Foo extends Bar {
Thinking in Java 3rd Edition
第 15 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
接下来的定义就完全相g2528了。
g3926g7536g1332创建了一g1022新的package,g5194且g1866中g7588g1022类还g13499承了另一g1022
packageg18336g19766的类,那么g1332g2494能访问g2419先那g1022package的publicg6116
员。(当g9994g3926g7536是在g2528一g1022packageg18336g19766g13499承的g16817,那么g1332还g2499以访问
package权限的g6116员。)有时基类的创建g13785g1262希望派生类能访问g7588g1022g6116
员,g13792g1866它类g2029不能访问。这就是protected要做的。protected也赋予g6116员package权限——也就是说,g2528一g1022packageg18336的g1866它类也
g2499以访问protected元素。
g3926g7536g1332回上去看Cookie.java,就g1262g2469g10628下g19766这g1022类是不能g16855g11004
package权限的bite( )的,
//,c05:ChocolateChip.java
// Can't use package-access member from another
package,
import com.bruceeckel.simpletest.*;
import c05.dessert.*;
public class ChocolateChip extends Cookie {
private static Test monitor = new Test();
public ChocolateChip() {
System.out.println("ChocolateChip constructor");
}
public static void main(String[] args) {
ChocolateChip x = new ChocolateChip();
//! x.bite(); // Can't access bite
monitor.expect(new String[] {
"Cookie constructor",
"ChocolateChip constructor"
});
}
} ///:~
g13499承有一g1022有趣的特g5627,就是g3926g7536Cookie类g18336一g1022bite( )g7053法,那么所有g13499承Cookie的类g18336也g18129有bite( )g7053法。但是bite( )是
package权限的,g5194且在另一g1022packageg18336g19766,g3252g8504我们g8821法g11004。当g9994
g1332g2499以把它做g6116public的,但是这g7691一来任g1321g1166g18129g2499以访问这g1022g7053法了,g13792这g2460不是g1332所希望的。但是,g3926g7536g1332这g7691g1474g6925Cookie,
public class Cookie {
public Cookie() {
System.out.println("Cookie constructor");
}
protected void bite() {
System.out.println("bite");
}
}
Chapter 5,Hiding the Implementation
第 16 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
那么在dessert packageg18336,bite( )仍g9994是package权限的,但是
g13499承Cookie的类也能访问它了。但它却不是public的。
接口(Interface)与实现(implementation)
访问权限通g5132被g12228g1038g256隐藏g4466g10628(implementation hiding)g257。在将数据和g7053法集g6116到了类g18336的g2528时,完g6116g256隐藏g4466g10628g257,这g12193做法g5132被g12228g1038g4565g16025
(encapsulation)。[29] g1866g13479g7536就是数据类型有了特g5461和g15904g1038。
有两g1022g18337要的g2419g3252要g16765我们g1038数据类型设g13634边g11040。首先就是要告诉客户g12255
序员,他们能g1363g11004哪g1135东西,不能g11004哪g1135东西。g1332g2499以在系g13491g18336g7512建g14270己的内部g7438制,这g7691就不必g6297心客户g12255序员g1262一不g4579心就把这部分东西当作接口来g11004了。
这一点g2460g11464接牵g9053到了第二g1022g2419g3252,这就是接口g994g4466g10628的分离。g3926g7536这g12193
g13479g7512被g11004于一组g12255序,那么客户g12255序员除了能向public接口g2469g17877消g5699之
g3818就什么也做不了,这g7691g1332就能g14270由地g1474g6925那g1135g19762public的 (g2265g6336
package权限,protectedg6122private)的g6116员,g13792不g11004g6297心g1262g11784坏客户代g11733了。
g10628在,我们是在g19766向g4557象g13546g12255的g1002g11040中,class的g5859思g4466g19481上是g6363g256一类
g4557象g257,就像g1332在说g21072类g6122g21491类。所有属于这一类的g4557象g18129有g7588g1135共g2528的特g5461g6122g15904g1038。类就是在g6563g17860这g1135g4557象是什么g7691g4388的,是g5602g7691工作的。
在最g7101的OOPg16833言,Simula-67中,关键g16801class是g11004来g6563g17860一g12193新的数据类型的。g13489g3835多数的g19766向g4557象的g16833言g18129g8851g11004了这g1022关键g16801。它点g7138
了OOPg16833言的关键:创建一g12193新的数据类型,g13792不g1177g1177是把数据和g7053法做在一g1022g8181g3371g18336。
类是Java的OOPg8022念的基础。它也是本书不g11004g12907g1319g15932g12046的关键g16801之一——要把像g256classg257这g7691出g10628g20069g10587g7509g20652的g16801做这g12193处g10714g1262是g19762g5132g9914g1166
的。
g1038了g16765代g11733g7186g5483g7368有条g10714,g2499能g1332选g11004这g12193g20130g7696,就是将publicg6116员g18129
放在类的开g3848,接下来是protectedg6116员,g9994后是package权限的,
最后是privateg6116员。这g7691做的g3921处就是,当g11004户从上到下g16847代g11733的时候,g1262先看到g4557他们最g18337要的东西(就是能在g7003件以g3818访问的publicg6116
员)。g13792当他们遇到g19762publicg6116员的时候,就g1262知道这是类的内部g4466g10628
部分,这g7691就g2499以不g16847下去了。
public class X {
public void pub1() { /*,,,*/ }
public void pub2() { /*,,,*/ }
Thinking in Java 3rd Edition
第 17 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
public void pub3() { /*,,,*/ }
private void priv1() { /*,,,*/ }
private void priv2() { /*,,,*/ }
private void priv3() { /*,,,*/ }
private int i;
//,,,
}
由于接口和g4466g10628仍g9994是g9163在一起的,g3252g8504这g12193g1901法g2494能部分地减g17743g16847g13785的
g17139g6297。也就是说,g1332还g5483g16847g9316代g11733,也就是g1866g4466g10628部分,g3252g1038它就在类
g18336。g8504g3818javadoc(第2g12468g16774的)生g6116的注g18334g7003g7735也g3835g3835g19489g1314了客户g12255序员要g16847g9316代g11733的必要g5627。g4466g19481上,向g11004户g4649g12046接口应该是g256类g8995g16284g3132(class
browser)g257的工作。所谓类g8995g16284g3132是一g12193工g1867,它能g6226出所有的类,g5194
且告诉g1332,应该g11004什么g7053法来g1363g11004这g1135类(比g3926g2499以g11004哪g1135g6116员)。类g8995g16284
g3132g5062g13475g6116g1038g1260g12180的Java开g2469工g1867所必不g2499g4581的组g6116部分了。
类的访问权限
Java的访问控制符还能g11004于类,这时它g1262决定,g11004户能g3827g1363g11004类库g18336的哪g1135类。g3926g7536要g1813许客户g12255序员g1363g11004一g1022类,g1332g2499以g11004public关键g16801来定义这g1022类。它g1262控制,客户g12255序员能g2554创建这g1022类的g4557象。
要想控制类的访问权限,控制符必须放在class关键g16801的前g19766。g3252g8504g1332
应该这g7691g1901,
public class Widget {
g3926g7536g1332的类库的g2529g4395是mylib,那么客户g12255序员就能这g7691g1363g11004Widget
了,
import mylib.Widget;
g6122g13785
import mylib.*;
但是还有一g1135g20081g3818的限制,
Chapter 5,Hiding the Implementation
第 18 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
1,g8611g1022g13546译单元(g7003件)g2494能有一g1022public类。这么做的g5859思是,g8611g1022g13546
译单元g2494能有一g1022公开的接口,g13792这g1022接口就由g1866public类来g15932g12046。
g1332g2499以g7693据g19668要,往这g1022g7003件g18336g19766g9167g2164任g5859多g1022提供g17753g2173功能的
package权限的类。但是g3926g7536这g1022g13546译单元g18336g19766有两g1022g6122两g1022以上的
public类的g16817,g13546译g3132就g1262g6265g19181。
2,public类的g2529g4395必须和这g1022g13546译单元的g7003件g2529完全相g2528,g2265g6336g3835g4579
g1901。所以g4557Widget类,g7003件g2529必须是Widget.java,不能是
widget.javag6122WIDGET.java。g3926g7536g1332不遵守,g13546译g3132g2460要g6265g19181
了。
3,g13546译单元g18336g19766g2499以g8821有public类,g15441g9994这g12193情g1929不g5132见,但却是g2499以的。这时,g1332就能g19555g5859g1038g7003件起g2529g4395了。
g3926g7536mylibg18336g19766还有一g1022要g1038Widgetg6122mylib的g1866它public类提供g7393g2165的类,那g1332g2460该g5602么做呢g731g1332不想g1038客户g12255序员g1901g7003g7735,g3252g1038g1332知道,g2499能过段时间g1332就g1262g11004一g1022新的类来替换它了。要想能g14731g5483这g12193g9801g8975
g5627,g1332就必须确保客户g12255序员不能利g11004mylib的内部g4466g10628来g13546g12255。g1038了达g6116这g1022目g7643,g1332g2494要将public关键g16801从类g18336删掉就g15904了,这g7691它就是
package权限的了。(于是类g2494能g11004于package内部了。)
创建package权限的类时,将类的g6116员定义g6116private,仍g9994g1262是g5468g7138
g7246的——g1332应该尽g18339地将g6116员g18129设g6116private的——但是通g5132情g1929下,
还是应该将g7053法的访问权限设g6116和类的一g7691(也就是说,g7053法也设g6116
package的)。由于package权限的类g2494g1262g11004于package的内部,g3252g8504
g4466在g8821g2162法的时候,g2494要将这g1135g7053法设g6116public的就g15904了。g11908到这g12193情
g1929的时候,g13546译g3132g1262通知g1332的。
注g5859,类不能是private(这g7691除了这g1022类g14270己,g1866它g1166g18129不能访问了)g6122
protected的。[30]g3252g8504类g2494有两g12193访问权限:package权限和
public。g3926g7536g1332不希望别g1166访问这g1022类,g1332g2499以将它的g7512g17908函数做g6116
private的,这g7691除g1332之g3818,g8821g1166g2499以创建那g1022类的g4557象了。g13792g1332g2029g2499
以g1363g11004一g1022staticg7053法来创建g4557象。下g19766就是一例,
//,c05:Lunch.java
// Demonstrates class access specifiers,Make a
class
// effectively private with private constructors,
class Soup {
private Soup() {}
// (1) Allow creation via static method,
public static Soup makeSoup() {
return new Soup();
}
// (2) Create a static object and return a
reference
// upon request.(The "Singleton" pattern),
private static Soup ps1 = new Soup();
public static Soup access() {
return ps1;
Thinking in Java 3rd Edition
第 19 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
}
public void f() {}
}
class Sandwich { // Uses Lunch
void f() { new Lunch(); }
}
// Only one public class allowed per file,
public class Lunch {
void test() {
// Can't do this! Private constructor,
//! Soup priv1 = new Soup();
Soup priv2 = Soup.makeSoup();
Sandwich f1 = new Sandwich();
Soup.access().f();
}
} ///:~
g17816今g1038止,g13489g3835多数的g7053法g18129是voidg6122g17832回primitive类型的,所以刚看到这g1022定义,
public static Soup access() {
return ps1;
}
的时候,g1262有点不知所g1125。g7053法g2529g4395(access)前g19766的那g1022单g16801g1262告诉
g1332,这g1022g7053法应该g17832回什么类型的数据。到目前g1038止,我们看到最多的是
void,它的g5859思是什么g18129不g17832回。但是g1332也g2499以g16765它g17832回一g1022g4557象的
reference,g13792这就是这段g12255序的g5859思。这g1022g7053法g1262g17832回一g1022Soupg4557象的reference。
class Soup演g12046了,g5602g7691g11004privateg7512g17908函数来禁止g11004户g11464接创建g7588
g1022类的g4557象。g16772g1315,要是g1332一g1022g7512g17908函数g18129不g1901的g16817,g13546译g3132就g1262g1038g1332合
g6116一g1022默g16760的g7512g17908函数(即g7092参数的g7512g17908函数)。g1901了默g16760的g7512g17908函数之后,它也不g1262g1889g1038g1332创建了。g7512g17908函数定义g6116private之后,就g8821g1166能创建那g1022类的g4557象了。那么它g2460该g5602g7691g1363g11004呢g731上g19766的例g4388g13485出了两g12193g7053
法。第一g12193,就是定义一g1022g1262创建Soupg4557象,g5194且g1262g17832回g1866
reference的staticg7053法。g3926g7536g1332想先做一g1135g6817作,g1889g17832回g4557象的
reference,g6122g13785要计g12651一下Soupg4557象的数g18339(g2499能是g1038了限制g1866数
g18339),那么这g12193做法还是g5468有g11004的。
第二g12193g7053法就是我们所说的设计g8181g5347(design pattern)。设计g8181g5347要在的
Thinking in Patterns(with Java)这本书g18336g16774,这本书也g2499以到
www.BruceEckel.com去下g17745。这g18336g11004到的是被g12228g1038g256singletong257的
Chapter 5,Hiding the Implementation
第 20 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
g8181g5347,g3252g1038它g2494g1813许g1332创建一g1022这g12193类的g4557象。这g1022g4557象是被当作Soup
类的static privateg6116员来创建的,g3252g8504它有且g2494有一g1022g4557象,g13792且除
g19762是通过public的access( )g7053法,g2554g2029g8821法g14731g2474。
正g3926我们前g19766所提到的,g3926g7536g1332不g1901类的访问控制符,那么它就默g16760是
package权限的。也就是说,package中的任g1321一g1022类g18129能创建这g1022类的g4557象,但是package以g3818的类就不g15904了。(g16772g1315,g2528一g1022目g5417g18336g19766的g1866
它g7003件,g2494要g8821有g2265g2559packageg16833g2489,就g18129g1262被默g16760g1038是这g1022目g5417的
package权限的。)但是g3926g7536这g1022类有一g1022public的staticg6116员,那么即便客户g12255序员不能创建那g1022类的g4557象,他们也还g2499以访问这g1022
static的g6116员。
总结
不g16782参g994各g7053有什么利g4487关系,能有一g1022g1038各g7053所g4574g18337的g11040限是g5468g18337要的。当g1332创建类库的时候,g1332就g994类库的g1363g11004g13785,也就是客户g12255序员们,
建g12447了一g12193关系。他们也是g12255序员,他们要g11004类库来组建一g1022应g11004g12255序,
g6122g13785在g1332的类库的基础上g7512建一g1022g7368g3835的类库。
要是g8821有规g2029的g16817,即便g1332不想g16765客户g12255序员们去g11464接g6817控类的g7588g1135g6116
员,g1332也g8821法去阻止他们。一切g18129g7304g19718在g3818g19766,什么g17986g11434也g8821有。
本g12468g1039题是g5602g7691g11004类来g7512建类库:首先是g5602g7691将类g4565g16025g6116类库,g9994后是,
类是g5602g7691控制它的g6116员的访问权限的。
曾g13475有g1166做过g16792g1284,说C的项目在达到50,000到100,000g15904的时候就开始g4861g9303了,g3252g1038Cg2494有一g1022g256g2529g4395g12366间g257,g13792g2529g4395g1926g12373g1262引g2469g20081g3818的管
g10714的g17139g6297。但是Javag16833言的package关键g16801,package的g2641g2529规
g14551,以及import关键g16801,能g16765g1332g4557g2529g4395g4466g7057完全的控制,g3252g8504g2499以g5468
容易的化g16311g2529g4395g1926g12373。
有两g1022g2419g3252g1431g1363我们要g4557类的g6116员进g15904访问权限g7053g19766的控制。一是,要禁止g11004户去g11908他们不该g11908的东西,也就是那g1135不属于供g11004户g16311决问题之g11004的接口,g13792是属于g9053及类的内部g17828作的工g1867。g3252g8504我们说将g7053法和g4395段定义
g6116private的,是g4557g11004户提供的一g12193g7393g2165,g3252g1038他们能g11464接了g16311什么是
g18337要的,什么是g2499以不去g10714g1262的。这g12628化了他们g4557类的g10714g16311。
第二g1022也是最g18337要的g2419g3252就是,要g16765类库的设计g13785们能在不g5790动客户g12255序员的前提下g1474g6925类库的内部g17828g15904g7053g5347。g2499能g1332g1262先g11004一g12193思g17347来创建类,
g9994后g2469g10628g18337新规g2022一下能g16765它g17317g5483g7368g5567。g3926g7536接口和g4466g10628被分g5483g5468g9177g7982,
g13792且访问控制也做g5483g5468g3921,那么g1332就能在做到这一点了。
Java的访问控制符赋予类的开g2469g1166员一g12193g5468有价值的能g2159。g11004户能g3827g5468
g9177g7982地知道,哪g1135是他们g2499以g11004的,哪g1135是他们g2499以g5585g11065的。但是g7368g18337要
Thinking in Java 3rd Edition
第 21 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
的是,这是一g12193能确保g11004户不g1262依赖类的内部g4466g10628来g13546g12255的手段。作g1038类的创建g13785,g3926g7536g1332g10714g16311了这一点,就g2499以g19555心所g8454的g1474g6925类的底g4630g4466g10628
了,g3252g1038g1332知道客户g12255序员们g7092须g1474g6925他们的代g11733;g3252g1038他们g7693本访问不到这部分。
当g1332能g14731g5483了g1474g6925类的底g4630g4466g10628的能g2159的时候,g1332就有权利g19555时g1474g6925类的设计了。g2528g7691g1332也有了g10371g19181g16835的权利。g7092g16782计g2022g3926g1321g2620g16826,设计g3926g1321g12946
g5051,g1332g18129g1262g10371g19181g16835。当g1332知道即g1363g10371了g19181g16835也g8821什么g3835不了的时候,g1332就
g1262变g5483g7368g4512g4466g20576g12946神了。于是,g1332g1262学g5483g7368g5567,项目也能完g6116g5483g7368g7101。
类的公开接口是g11004户g4466g4466在在看到的部分,g3252g8504在分g7524和设计g19466段,它是类是g2554g256正确g257的决定g3252素。即g1363是这g7691,g1332还是g2499以做g1474g6925的。g3926g7536第一g8437g8821能g13485出正确的接口,那以后还g2499以g9167g2164,g2494是不能删除客户g12255序员
g5062g13475g11004到过的东西了。
练习
g2494要g1196g5468g4579一g12520g17165g11004就能从www.BruceEckel.com下g17745g2529g1038The
Thinking in Java Annotated Solution Guide的g11017g4388g7003g7735,这上g19766有一g1135习题的g12584g7708。
1,g1901一段g1262创建ArrayListg4557象的g12255序,不要g11004import
java.util.*。
2,g6226到g256package:类库的单元g257一g14422中g994mypackage有关的代g11733g10267
g7041,将它g6925g1901g6116一组能g13546译g17828g15904的Javag9316g7003件。
3,g6226到g256g1926g12373g257一g14422的代g11733g10267g7041,将它g6925g1901g6116一g1022g12255序,g9994后g20576g16789一下,
看看g1926g12373是不是g11507的g1262g2469生。
4,g4557本g12468所定义的P类做一g14336化处g10714,g18337g17745rint( )和rintln( )g7053法,
g1363之能处g10714各g12193Java数据类型。
5,创建一g1022有public,private,protected,和package访问权限的数据的类。创建一g1022这g1022类的g4557象,g9994后看看,当g1332要访问这g1135数据的时候,g13546译g3132g18129g1262g13485一g1135什么消g5699。提g18278一下,g2528一g1022目g5417g18336g19766的g1866
它类也是g256默g16760g257package的一部分。
6,创建一g1022有protected数据的类。g9994后在g2528一g1022g9316g7003件g18336创建一g1022
类,这g1022类要有一g1022能g6817控第一g1022类的protected数据的g7053法。
7,g1474g6925g256protected:g13499承的访问权限g257一g14422中的Cookie类。g20576g16789一下,bite( )不是public的。
8,在g256类的访问权限g257一g14422中,g6226到g16774g17860mylib和Widget的代g11733。g9994
后把这g1022类库g1901出来,g1889g1901一g1022不属于mylib package的类,g9994后在这g1022类g18336创建一g1022Widgetg4557象。
9,创建一g1022新的目g5417g5194且把它g2164到CLASSPATH中。把P.classg7003件(g13546
译com.bruceeckel.tools.P.java生g6116的)g6347g17137到这g1022目g5417g18336,g9994
Chapter 5,Hiding the Implementation
第 22 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
后g1474g6925g7003件g2529,g18336g19766P类的g2529g12228,以及g1866g7053法g2529。(g1332g2499以g16765它多g17767出
g1135东西,看看它是g5602g7691工作的。)在另一g1022目g5417g18336g19766创建一g1022要g1363g11004这g1022
新类的类。
10,参g10043Lunch.javag1901一g1022ConnectionManager类,g9994后g11004它去管g10714一组g3278定数g18339的Connectiong4557象。要做到,客户g12255序员不能g11464
接创建,g13792g2494能通过ConnectionManager的staticg7053法来g14731g2474
Connectiong4557象。当ConnectionManageg7092g4557象g2499分配的时候,它g1262g17832回null的reference。g11004main( )做g8991试。
11,在c05/local目g5417创建下g19766这g1022g7003件(g1563设CLASSPAHg18336g19766有这g1022目
g5417),Create the following file in the c05/local directory
(presumably in your CLASSPATH),
// c05:local:PackagedClass.java
package c05.local;
class PackagedClass {
public PackagedClass() {
System.out.println("Creating a packaged class");
}
}
g9994后在c05以g3818的目g5417g18336创建下g19766这g1022g7003件,
// c05:foreign:Foreign.java
package c05.foreign;
import c05.local.*;
public class Foreign {
public static void main (String[] args) {
PackagedClass pc = new PackagedClass();
}
}
g16311g18334一下g13546译g3132g1038什么g1262g6265g19181。把这g1022Foreign类做g6116c05.local
package的g1262不g1262有什么不g2528g731
[26] Java也不是g19762要g11004g16311g18334g3132不g2499。有一g1135Java本地代g11733g13546译g3132能生g6116
单g10432的g2499g6203g15904的g7003件。
[27]g10627g3671变g18339要g11004g3835g1901(CLASSPATH)。
[28]这g12193做法还g1262产生一g1022后g7536:由于g2494定义了一g1022默g16760的g7512g17908函数,g13792
且还是private的,g3252g8504要g13499承这g1022类就变g5483不g2499能了。(这是第6g12468的内容。)
[29]但是g1166们g5132g1262把g4565g16025g2494g10714g16311g1038g256隐藏g4466g10628g257。
Thinking in Java 3rd Edition
第 23 页 共 23 www.wgqqh.com/shhgs/tij.html
email,shhgs@sohu.com
[30]g4466g19481上内部类(inner class)g2499以是privateg6122protected,但这是特例。我们g1262在第7g12468g1889作g16764g16782。