八宝书库 > 文学其他电子书 > Java编程思想第4版[中文版](PDF格式) >

第174部分

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

小说: Java编程思想第4版[中文版](PDF格式) 字数: 每页4000字

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




public interface Face {  

  public void smile();  

}  

public class Baz extends Bar implements Face {  

  public void smile( ) {  

    System。out。println(〃a warm smile〃);  

  }  

}  

  

(34) Java 中没有virtual 关键字,因为所有非static 方法都肯定会用到动态绑定。在Java 中,程序员不 

必自行决定是否使用动态绑定。C++之所以采用了 virtual,是由于我们对性能进行调整的时候,可通过将其 

省略,从而获得执行效率的少量提升(或者换句话说:“如果不用,就没必要为它付出代价”)。virtual 

经常会造成一定程度的混淆,而且获得令人不快的结果。final 关键字为性能的调整规定了一些范围——它 

向编译器指出这种方法不能被取代,所以它的范围可能被静态约束(而且成为嵌入状态,所以使用C++非 

virtual 调用的等价方式)。这些优化工作是由编译器完成的。  

(35) Java不提供多重继承机制(MI),至少不象C++那样做。与 protected 类似,MI 表面上是一个很不错 

的主意,但只有真正面对一个特定的设计问题时,才知道自己需要它。由于Java 使用的是“单根”分级结 

构,所以只有在极少的场合才需要用到MI。interface 关键字会帮助我们自动完成多个接口的合并工作。  

(36) 运行期的类型标识功能与C++极为相似。例如,为获得与句柄 X 有关的信息,可使用下述代码:  

X。getClass()。getName();  

为进行一个“类型安全”的紧缩造型,可使用:  

derived d = (derived)base;  

这与旧式风格的C 造型是一样的。编译器会自动调用动态造型机制,不要求使用额外的语法。尽管它并不象 

C++的“new casts ”那样具有易于定位造型的优点,但Java 会检查使用情况,并丢弃那些“异常”,所以它 

不会象C++那样允许坏造型的存在。  

(37) Java采取了不同的异常控制机制,因为此时已经不存在构建器。可添加一个finally 从句,强制执行 

特定的语句,以便进行必要的清除工作。Java 中的所有异常都是从基础类Throwable 里继承而来的,所以可 

确保我们得到的是一个通用接口。  

  

public void f(Obj b) throws IOException {  

  myresource mr = b。createResource();  

  try {  

    mr。UseResource();  

  } catch (MyException e) {   

    // handle my exception  

  } catch (Throwable e) {   

    // handle all other exceptions  

  } finally {  

    mr。dispose(); // special cleanup  

  }  

}  

  

(38) Java的异常规范比C++的出色得多。丢弃一个错误的异常后,不是象C++那样在运行期间调用一个函 

数,Java 异常规范是在编译期间检查并执行的。除此以外,被取代的方法必须遵守那一方法的基础类版本的 

异常规范:它们可丢弃指定的异常或者从那些异常衍生出来的其他异常。这样一来,我们最终得到的是更为 

 “健壮”的异常控制代码。  

(39) Java具有方法过载的能力,但不允许运算符过载。String 类不能用+和+=运算符连接不同的字串,而且 

String 表达式使用自动的类型转换,但那是一种特殊的内建情况。  

(40) 通过事先的约定,C++中经常出现的const 问题在Java 里已得到了控制。我们只能传递指向对象的句 

柄,本地副本永远不会为我们自动生成。若希望使用类似 C++按值传递那样的技术,可调用 clone(),生成自 

变量的一个本地副本(尽管clone()的设计依然尚显粗糙——参见第 12 章)。根本不存在被自动调用的副本 



                                                                                    675 


…………………………………………………………Page 677……………………………………………………………

构建器。为创建一个编译期的常数值,可象下面这样编码:  

static final int SIZE = 255  

static final int BSIZE = 8 * SIZE  

(41) 由于安全方面的原因,“应用程序”的编程与“程序片”的编程之间存在着显著的差异。一个最明显的 

问题是程序片不允许我们进行磁盘的写操作,因为这样做会造成从远程站点下载的、不明来历的程序可能胡 

乱改写我们的磁盘。随着Java 1。1 对数字签名技术的引用,这一情况已有所改观。根据数字签名,我们可确 

切知道一个程序片的全部作者,并验证他们是否已获得授权。Java 1。2 会进一步增强程序片的能力。  

(42) 由于Java 在某些场合可能显得限制太多,所以有时不愿用它执行象直接访问硬件这样的重要任务。 

Java 解决这个问题的方案是“固有方法”,允许我们调用由其他语言写成的函数(目前只支持C 和C++)。 

这样一来,我们就肯定能够解决与平台有关的问题(采用一种不可移植的形式,但那些代码随后会被隔离起 

来)。程序片不能调用固有方法,只有应用程序才可以。  

(43) Java提供对注释文档的内建支持,所以源码文件也可以包含它们自己的文档。通过一个单独的程序, 

这些文档信息可以提取出来,并重新格式化成 HTML 。这无疑是文档管理及应用的极大进步。  

(44) Java包含了一些标准库,用于完成特定的任务。C++则依靠一些非标准的、由其他厂商提供的库。这些 

任务包括(或不久就要包括):  

■连网  

■数据库连接(通过JDBC )  

■多线程  

■分布式对象(通过RMI 和 CORBA)  

■压缩  

■商贸  

由于这些库简单易用,而且非常标准,所以能极大加快应用程序的开发速度。  

(45) Java 1。1包含了 Java Beans 标准,后者可创建在可视编程环境中使用的组件。由于遵守同样的标准, 

所以可视组件能够在所有厂商的开发环境中使用。由于我们并不依赖一家厂商的方案进行可视组件的设计, 

所以组件的选择余地会加大,并可提高组件的效能。除此之外,Java Beans 的设计非常简单,便于程序员理 

解;而那些由不同的厂商开发的专用组件框架则要求进行更深入的学习。  

(46) 若访问 Java 句柄失败,就会丢弃一次异常。这种丢弃测试并不一定要正好在使用一个句柄之前进行。 

根据Java 的设计规范,只是说异常必须以某种形式丢弃。许多C++运行期系统也能丢弃那些由于指针错误造 

成的异常。  

(47) Java通常显得更为健壮,为此采取的手段如下:  

■对象句柄初始化成null (一个关键字)  

■句柄肯定会得到检查,并在出错时丢弃异常  

■所有数组访问都会得到检查,及时发现边界违例情况  

■自动垃圾收集,防止出现内存漏洞  

■明确、“傻瓜式”的异常控制机制  

■为多线程提供了简单的语言支持  

■对网络程序片进行字节码校验  



                                                                676 


…………………………………………………………Page 678……………………………………………………………

                        附录 C Java 编程规则  



  

本附录包含了大量有用的建议,帮助大家进行低级程序设计,并提供了代码编写的一般性指导:  

  

(1) 类名首字母应该大写。字段、方法以及对象(句柄)的首字母应小写。对于所有标识符,其中包含的所 

有单词都应紧靠在一起,而且大写中间单词的首字母。例如:  

ThisIsAClassName  

thisIsMethodOrFieldName  

若在定义中出现了常数初始化字符,则大写static final基本类型标识符中的所有字母。这样便可标志出它 

们属于编译期的常数。  

Java 包(Package)属于一种特殊情况:它们全都是小写字母,即便中间的单词亦是如此。对于域名扩展名 

称,如 ,org,net 或者edu 等,全部都应小写(这也是Java 1。1 和 Java 1。2 的区别之一)。  

(2) 为了常规用途而创建一个类时,请采取“经典形式”,并包含对下述元素的定义:  

equals()  

hashCode()  

toString()  

clone() (implement Cloneable)  

implement Serializable  

(3) 对于自己创建的每一个类,都考虑置入一个main(),其中包含了用于测试那个类的代码。为使用一个项 

目中的类,我们没必要删除测试代码。若进行了任何形式的改动,可方便地返回测试。这些代码也可作为如 

何使用类的一个示例使用。  

(4) 应将方法设计成简要的、功能性单元,用它描述和实现一个不连续的类接口部分。理想情况下,方法应 

简明扼要。若长度很大,可考虑通过某种方式将其分割成较短的几个方法。这样做也便于类内代码的重复使 

用(有些时候,方法必须非常大,但它们仍应只做同样的一件事情)。  

(5) 设计一个类时,请设身处地为客户程序员考虑一下(类的使用方法应该是非常明确的)。然后,再设身 

处地为管理代码的人考虑一下(预计有可能进行哪些形式的修改,想想用什么方法可把它们变得更简单)。  

(6) 使类尽可能短小精悍,而且只解决一个特定的问题。下面是对类设计的一些建议:  

■一个复杂的开关语句:考虑采用“多形”机制  

■数量众多的方法涉及到类型差别极大的操作:考虑用几个类来分别实现  

■许多成员变量在特征上有很大的差别:考虑使用几个类  

(7) 让一切东西都尽可能地“私有”——private。可使库的某一部分“公共化”(一个方法、类或者一个字 

段等等),就永远不能把它拿出。若强行拿出,就可能破坏其他人现有的代码,使他们不得不重新编写和设 

计。若只公布自己必须公布的,就可放心大胆地改变其他任何东西。在多线程环境中,隐私是特别重要的一 

个因素——只有private 字段才能在非同步使用的情况下受到保护。  

(8) 谨惕“巨大对象综合症”。对一些习惯于顺序编程思维、且初涉OOP 领域的新手,往往喜欢先写一个顺 

序执行的程序,再把它嵌入一个或两个巨大的对象里。根据编程原理,对象表达的应该是应用程序的概念, 

而非应用程序本身。  

(9) 若不得已进行一些不太雅观的编程,至少应该把那些代码置于一个类的内部。  

(10) 任何时候只要发现类与类之间结合得非常紧密,就需要考虑是否采用内部类,从而改善编码及维护工作 

 (参见第14 章 14。1。2 小节的“用内部类改进代码”)。  

(11) 尽可能细致地加上注释,并用 javadoc 注释文档语法生成自己的程序文档。  

(12) 避免使用“魔术数字”,这些数字很难与代码很好地配合。如以后需要修改它,无疑会成为一场噩梦, 

因为根本不知道“100”到底是指“数组大小”还是“其他全然不同的东西”。所以,我们应创建一个常数, 

并为其使用具有说服力的描述性名称,并在整个程序中都采用常数标识符。这样可使程序更易理解以及更易 

维护。  

(13) 涉及构建器和异常的时候,通常希望重新丢弃在构建器中捕获的任何异常——如果它造成了那个对象的 

创建失败。这样一来,调用者就不会以为那个对象已正确地创建,从而盲目地继续。  

(14) 当客户程序员用完对象以后,若你的类要求进行任何清除工作,可考虑将清除代码置于一个良好定义的 

方法里,采用类似于cleanup()这样的名字,明确表明自己的用途。除此以外,可在类内放置一个boolean 

 (布尔)标记,指出对象是否已被清除。在类的finalize()方法里,请确定对象已被清除,并已丢弃了从 



                                                                    677 


…………………………………………………………Page 679……………………………………………………………

RuntimeException 继承的一个类(如果还没有的话),从而指出一个编程错误。在采取象这样的方案之前, 

请确定 finalize()能够在自己的系统中工作(可能需要调用 System。runFinalizersOnExit(true),从而确保 

这一行为)。  

(15) 在一个特定的作用域内,若一个对象必须清除(非由垃圾收集机制处理),请采用下述方法:初始化对 

象;若成功,则立即进入一个含有 finally 从句的 try 块,开始清除工作。  

(16) 若在初始化过程中需要覆盖(取消)finalize(),请记住调用super。finalize() (若Object 属于我们 

的直接超类,则无此必要)。在对 finalize()进行覆盖的过程中,对 super。finalize()的调用应属于最后一 

个行动,而不应是第一个行动,这样可确保在需要基础类组件的时候它们依然有效。  

(17) 创建大小固定的对象集合时,请将它们传输至一个数组(若准备从一个方法里返回这个集合,更应如此 

操作)。这样一来,我们就可享受到数组在编译期进行类型检查的好处。此外,为使用它们,数组的接收者 

也许并不需要将对象“造型”到数组里。  

(18) 尽量使用 interfaces,不要使用 abstract 类。若已知某样东西准备成为一个基础类,那么第一个选择 

应是将其变成一个 interface (接口)。只有在不得不使用方法定义或者成员变量的时候,才需要将其变成 

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

返回目录 上一页 下一页 回到顶部 0 1

你可能喜欢的