友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
富士康小说网 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

Java编程思想第4版[中文版](PDF格式)-第117部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!



一个abstract (抽象)类。接口主要描述了客户希望做什么事情,而一个类则致力于(或允许)具体的实施 

细节。  

(19) 在构建器内部,只进行那些将对象设为正确状态所需的工作。尽可能地避免调用其他方法,因为那些方 

法可能被其他人覆盖或取消,从而在构建过程中产生不可预知的结果(参见第7 章的详细说明)。  

(20) 对象不应只是简单地容纳一些数据;它们的行为也应得到良好的定义。  

(21) 在现成类的基础上创建新类时,请首先选择“新建”或“创作”。只有自己的设计要求必须继承时,才 

应考虑这方面的问题。若在本来允许新建的场合使用了继承,则整个设计会变得没有必要地复杂。  

(22) 用继承及方法覆盖来表示行为间的差异,而用字段表示状态间的区别。一个非常极端的例子是通过对不 

同类的继承来表示颜色,这是绝对应该避免的:应直接使用一个“颜色”字段。  

(23) 为避免编程时遇到麻烦,请保证在自己类路径指到的任何地方,每个名字都仅对应一个类。否则,编译 

器可能先找到同名的另一个类,并报告出错消息。若怀疑自己碰到了类路径问题,请试试在类路径的每一个 

起点,搜索一下同名的。class文件。  

(24) 在Java 1。1 AWT 中使用事件“适配器”时,特别容易碰到一个陷阱。若覆盖了某个适配器方法,同时 

拼写方法没有特别讲究,最后的结果就是新添加一个方法,而不是覆盖现成方法。然而,由于这样做是完全 

合法的,所以不会从编译器或运行期系统获得任何出错提示——只不过代码的工作就变得不正常了。  

(25) 用合理的设计方案消除“伪功能”。也就是说,假若只需要创建类的一个对象,就不要提前限制自己使 

用应用程序,并加上一条“只生成其中一个”注释。请考虑将其封装成一个“独生子”的形式。若在主程序 

里有大量散乱的代码,用于创建自己的对象,请考虑采纳一种创造性的方案,将些代码封装起来。  

(26) 警惕“分析瘫痪”。请记住,无论如何都要提前了解整个项目的状况,再去考察其中的细节。由于把握 

了全局,可快速认识自己未知的一些因素,防止在考察细节的时候陷入“死逻辑”中。  

(27) 警惕“过早优化”。首先让它运行起来,再考虑变得更快——但只有在自己必须这样做、而且经证实在 

某部分代码中的确存在一个性能瓶颈的时候,才应进行优化。除非用专门的工具分析瓶颈,否则很有可能是 

在浪费自己的时间。性能提升的隐含代价是自己的代码变得难于理解,而且难于维护。  

(28) 请记住,阅读代码的时间比写代码的时间多得多。思路清晰的设计可获得易于理解的程序,但注释、细 

致的解释以及一些示例往往具有不可估量的价值。无论对你自己,还是对后来的人,它们都是相当重要的。 

如对此仍有怀疑,那么请试想自己试图从联机 Java 文档里找出有用信息时碰到的挫折,这样或许能将你说 

服。  

(29) 如认为自己已进行了良好的分析、设计或者实施,那么请稍微更换一下思维角度。试试邀请一些外来人 

士——并不一定是专家,但可以是来自本公司其他部门的人。请他们用完全新鲜的眼光考察你的工作,看看 

是否能找出你一度熟视无睹的问题。采取这种方式,往往能在最适合修改的阶段找出一些关键性的问题,避 

免产品发行后再解决问题而造成的金钱及精力方面的损失。  

(30) 良好的设计能带来最大的回报。简言之,对于一个特定的问题,通常会花较长的时间才能找到一种最恰 

当的解决方案。但一旦找到了正确的方法,以后的工作就轻松多了,再也不用经历数小时、数天或者数月的 

痛苦挣扎。我们的努力工作会带来最大的回报(甚至无可估量)。而且由于自己倾注了大量心血,最终获得 

一个出色的设计方案,成功的快感也是令人心动的。坚持抵制草草完工的诱惑——那样做往往得不偿失。  

(31) 可在Web 上找到大量的编程参考资源,甚至包括大量新闻组、讨论组、邮寄列表等。下面这个地方提供 

了大量有益的链接:  

http://ulb。ac。be/esp/ip…Links/Java/joodcs/mm…WebBiblio。html  



                                                             678 


…………………………………………………………Page 680……………………………………………………………

                               附录 D  性能  



  

 “本附录由Joe Sharp 投稿,并获得他的同意在这儿转载。请联系SharpJoe@aol。”  

  

Java 语言特别强调准确性,但可靠的行为要以性能作为代价。这一特点反映在自动收集垃圾、严格的运行期 

检查、完整的字节码检查以及保守的运行期同步等等方面。对一个解释型的虚拟机来说,由于目前有大量平 

台可供挑选,所以进一步阻碍了性能的发挥。  

 “先做完它,再逐步完善。幸好需要改进的地方通常不会太多。”(Steve McConnell 的《About  

performance》'16')  

本附录的宗旨就是指导大家寻找和优化“需要完善的那一部分”。  



D。1 基本方法  



只有正确和完整地检测了程序后,再可着手解决性能方面的问题:  

(1) 在现实环境中检测程序的性能。若符合要求,则目标达到。若不符合,则转到下一步。  

(2) 寻找最致命的性能瓶颈。这也许要求一定的技巧,但所有努力都不会白费。如简单地猜测瓶颈所在,并 

试图进行优化,那么可能是白花时间。  

(3) 运用本附录介绍的提速技术,然后返回步骤 1。  

  

为使努力不至白费,瓶颈的定位是至关重要的一环。Donald Knuth'9' 曾改进过一个程序,那个程序把50% 

的时间都花在约4%的代码量上。在仅一个工作小时里,他修改了几行代码,使程序的执行速度倍增。此 

时,若将时间继续投入到剩余代码的修改上,那么只会得不偿失。Knuth 在编程界有一句名言:“过早的优 

化是一切麻烦的根源”(Premature optimization is the root of all evil )。最明智的做法是抑制过早 

优化的冲动,因为那样做可能遗漏多种有用的编程技术,造成代码更难理解和操控,并需更大的精力进行维 

护。  



D。2  寻找瓶颈  



为找出最影响程序性能的瓶颈,可采取下述几种方法:  



D。2。1  安插自己的测试代码  



插入下述“显式”计时代码,对程序进行评测:  

  

long start = System。currentTimeMillis();  

// 要计时的运算代码放在这儿  

long time = System。currentTimeMillis() start;  

  

利用System。out。println(),让一种不常用到的方法将累积时间打印到控制台窗口。由于一旦出错,编译器 

会将其忽略,所以可用一个“静态最终布尔值”(Static final boolean)打开或关闭计时,使代码能放心 

留在最终发行的程序里,这样任何时候都可以拿来应急。尽管还可以选用更复杂的评测手段,但若仅仅为了 

量度一个特定任务的执行时间,这无疑是最简便的方法。  

System。currentTimeMillis()返回的时间以千分之一秒(1 毫秒)为单位。然而,有些系统的时间精度低于 1 

毫秒(如Windows PC),所以需要重复n 次,再将总时间除以n,获得准确的时间。  



D。2。2 JDK 性能评测'2'  



JDK 配套提供了一个内建的评测程序,能跟踪花在每个例程上的时间,并将评测结果写入一个文件。不幸的 

是,JDK 评测器并不稳定。它在 JDK 1。1。1 中能正常工作,但在后续版本中却非常不稳定。  

为运行评测程序,请在调用Java 解释器的未优化版本时加上…prof 选项。例如:  

java_g …prof myClass  

或加上一个程序片(Applet):  



                                                                       679 


…………………………………………………………Page 681……………………………………………………………

java_g …prof sun。applet。AppletViewer applet。html  

理解评测程序的输出信息并不容易。事实上,在JDK 1。0 中,它居然将方法名称截短为30 字符。所以可能无 

法区分出某些方法。然而,若您用的平台确实能支持…prof 选项,那么可试试 Vladimir Bulatov 的 

 “HyperPorf”'3'或者Greg White 的“ProfileViewer ”来解释一下结果。  



D。2。3  特殊工具  



如果想随时跟上性能优化工具的潮流,最好的方法就是作一些 Web 站点的常客。比如由Jonathan Hardwick 

制作的“Tools for Optimizing Java”(Java 优化工具)网站:  

http://cs。cmu。edu/~jch/java/tools。html  



D。2。4  性能评测的技巧  



     由于评测时要用到系统时钟,所以当时不要运行其他任何进程或应用程序,以免影响测试结果。  

     如对自己的程序进行了修改,并试图(至少在开发平台上)改善它的性能,那么在修改前后应分别测 

      试一下代码的执行时间。  

     尽量在完全一致的环境中进行每一次时间测试。  

     如果可能,应设计一个不依赖任何用户输入的测试,避免用户的不同反应导致结果出现误差。  



D。3 提速方法  



现在,关键的性能瓶颈应已隔离出来。接下来,可对其应用两种类型的优化:常规手段以及依赖Java 语言。  



D。3。1  常规手段  



通常,一个有效的提速方法是用更现实的方式重新定义程序。例如,在《Programming Pearls 》(编程拾 

贝)一书中'14',Bentley 利用了一段小说数据描写,它可以生成速度非常快、而且非常精简的拼写检查 

器,从而介绍了Doug McIlroy 对英语语言的表述。除此以外,与其他方法相比,更好的算法也许能带来更大 

的性能提升——特别是在数据集的尺寸越来越大的时候。欲了解这些常规手段的详情,请参考本附录末尾的 

 “一般书籍”清单。  



D。3。2  依赖语言的方法  



为进行客观的分析,最好明确掌握各种运算的执行时间。这样一来,得到的结果可独立于当前使用的计算 

机——通过除以花在本地赋值上的时间,最后得到的就是“标准时间”。  

  

运算 示例 标准时间  

  

本地赋值 i=n; 1。0  

实例赋值 this。i=n; 1。2  

int增值 i++; 1。5  

byte 增值 b++; 2。0  

short 增值 s++; 2。0  

float 增值 f++; 2。0  

double增值 d++; 2。0  

空循环 while(true) n++; 2。0  

三元表达式 (x》2 (或2 的任意次幂) 使用更快的硬件指令  



D。3。3  特殊情况  



■字串的开销:字串连接运算符+看似简单,但实际需要消耗大量系统资源。编译器可高效地连接字串,但变 

量字串却要求可观的处理器时间。例如,假设 s和 t 是字串变量:  

System。out。println(〃heading〃 + s + 〃trailer〃 + t);  

上述语句要求新建一个 StringBuffer (字串缓冲),追加自变量,然后用toString()将结果转换回一个字 

串。因此,无论磁盘空间还是处理器时间,都会受到严重消耗。若准备追加多个字串,则可考虑直接使用一 

个字串缓冲——特别是能在一个循环里重复利用它的时候。通过在每次循环里禁止新建一个字串缓冲,可节 

省980 单位的对象创建时间(如前所述)。利用 substring()以及其他字串方法,可进一步地改善性能。如 

果可行,字符数组的速度甚至能够更快。也要注意由于同步的关系,所以 StringTokenizer 会造成较大的开 

销。  

■同步:在JDK 解释器中,调用同步方法通常会比调用不同步方法慢 10 倍。经 JIT 编译器处理后,这一性能 

上的差距提升到50 到 100倍(注意前表总结的时间显示出要慢97 倍)。所以要尽可能避免使用同步方法— 

—若不能避免,方法的同步也要比代码块的同步稍快一些。  

■重复利用对象:要花很长的时间来新建一个对象(根据前表总结的时间,对象的新建时间是赋值时间的 

980 倍,而新建一个小数组的时间是赋值时间的3100 倍)。因此,最明智的做法是保存和更新老对象的字 

段,而不是创建一个新对象。例如,不要在自己的 paint()方法中新建一个Font 对象。相反,应将其声明成 

实例对象,再初始化一次。在这以后,可在paint()里需要的时候随时进行更新。参见 Bentley 编著的《编 

程拾贝》,p。81'15' 。  

■异常:只有在不正常的情况下,才应放弃异常处理模块。什么才叫“不正常”呢?这通常是指程序遇到了 

问题,而这一般是不愿见到的,所以性能不再成为优先考虑的目标。进行优化时,将小的“try…catch”块合 

并到一起。由于这些块将代码分割成小的、各自独立的片断,所以会妨碍编译器进行优化。另一方面,若过 

份热衷于删除异常处理模块,也可能造成代码健壮程度的下降。  

■散列处理:首先,Java 1。0 和 1。1 的标准“散列表”(Hashtable)类需要造型以及特别消耗系统资源的 

同步处理(570 单位的赋值时间)。其次,早期的 JDK 库不能自动决定最佳的表格尺寸。最后,散列函数应 

针对实际使用项(Key)的特征设计。考虑到所有这些原因,我们可特别设计一个散列类,令其与特定的应用 

程序配合,从而改善常规散列表的性能。注意 Java 1。2 集合库的散列映射(HashMap)具有更大的灵活性, 

而且不会自动同步。  

■方法内嵌:只有在方法属于final (最终)、private (专用)或static (静态)的情况下,Java 编译器 

才能内嵌这个方法。而且某些情况下,还要求它绝对不可以有局部变量。若代码花大量时间调用一个不含上 

述任何属性的方法,那么请考虑为其编写一个“final”版本。  

■I/O:应尽可能使用缓冲。否则,最终也许就是一次仅输入/输出一个字节的恶果。注意 JDK 1。0 的I/O 类 

采用了大量同步措施,所以若使用象readFully()这样的一个“大批量”调用,然后由自己解释数据,就可 

获得更佳的性能。也要注意Java 1。1 的“reader”和“writer”类已针对性能进行了优化。  

■造型和实例:造型会耗去2 到 200 个单位的赋值时间。开销更大的甚至要求上溯继承(遗传)结构。其他 



                                                                     681 


…………………………………………………………Page 683……………………………………………………………

高代价的操作会损失和恢复更低层结构的能力。  

■图形:利用剪切技术,减少在repaint()中的工作量;倍增缓冲区,提高接收速度;同时利用图形压缩技 

术,缩短下载时间。来自JavaWorld 的“Java Applets”以及来自 Sun 的“Performing Animation”是两个 

很好的教程。请记着使用最贴切的命令。例如,为根据一系列点画一个多边形,和drawLine()相比, 

drawPolygon()的速度要快得多。如必须画一条单像素粗细的直线,drawLine(x;y;x;y)的速度比 

fillRect(x;y;1;1)快。  

■使用API 类:尽量使用来自 Java API 的类,因为它们本身已针对机器的性能进行了优化。这是用Java 难 

于达到的。比如在复制任意长度的一个数组时,arraryCopy()比使用循环的速度快得多。  

■替换API 类:有些时候,API 类提供了比我们希望更多的功能,相应的执行时间也会增加。因此,可定做 

特别的版本,让它做更少的事情,但可更快地运行。例如,假定一个应用程序需要一个容器来保存大量数 

组。为加快执行速度,可将原来的 Vector (矢量)替换成更快的动态对象数组。  

  

1。 其他建议  

■将重复的常数计算移至关键循环之外——比如计算固定长度缓冲区的buffer。length 。  

■static final (静态最终)常数有助于编译器优化程序。  

■实现固定长度的循环。  

■使用javac 的优化选项:…O。它通过内嵌static,final 以及private 方法,从而优化编译过的代码。注 

意类的长度可能会增加(只对JDK 1。1 而言——更早的版本也许不能执行字节查证)。新型的“Just…in

time”(JIT)编译器会动态加速代码。  

■尽可能地将计数减至 0——这使用了一个特殊的JVM 字节码。  



D。4 参考资源  



D。4。1  性能工具  



'1' 运行于 Pentium Pro 200,Netscape 3。0,JDK 1。1。4 的MicroBenchmark (参见下面的参考资源'5')  

'2' Sun的Java 文档页——JDK Java 解释器主题:  

http://java。sun。/products/JDK/tools/win32/java。html  

'3' Vladimir Bulatov的HyperProf  

http://physics。orst。edu/~bulatov/HyperProf  

'4' Greg White 的ProfileViewer  

http://inetmi。/~gwhi/ProfileViewer/ProfileViewer。html  



D。4。2 Web 站点  



'5' 对于Java 代码的优化主题,最出色的在线参考资源是Jonathan Hardwick 的“Java Optimization”网 

站:  

http://cs。cmu。edu/~jch/java/optimization。html  

 “Java 优化工具”主页:  

http://cs。cmu。edu/~jch/java/tools。html  

以及“Java Microbenchmarks”(有一个45 秒钟的评测过程):  

http://cs。cmu。edu/~jch/java/benchmarks。html  



D。4。3  文章  



'6'  “Make Java fast:Optimize! How to get the greatest performanceout of your code through low

level optimizations in Java”(让Java 更快:优化!如何通过在Java 中的低级优化,使代码发挥最出色 

的性能)。作者:Doug Bell。网址:  

http://javaworld。/javaworld/jw…04…1997/jw…04…optimize。html  

 (含一个全面的性能评测程序片,有详尽注释)  

'7'  “Java Optimization Resources ”(Java 优化资源)  

http://cs。cmu。edu/~jch/java/resources。html  

'8'  “Optimizing Java for Speed”(优化Java,提高速度):  

http://cs。cmu。edu/~jch/java/speed。html  



                                                             
返回目录 上一页 下一页 回到顶部 10 9
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!