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

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

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


素,后者意味着“只能由继承者访问”(以前可用“private protected”实现这个目的,但这一对关键字的 

组合已被取消了)。  

(28) 嵌套的类。在C++中,对类进行嵌套有助于隐藏名称,并便于代码的组织(但C++的“命名空间”已使 

名称的隐藏显得多余)。Java 的“封装”或“打包”概念等价于 C++的命名空间,所以不再是一个问题。 

Java 1。1 引入了“内部类”的概念,它秘密保持指向外部类的一个句柄——创建内部类对象的时候需要用 

到。这意味着内部类对象也许能访问外部类对象的成员,毋需任何条件——就好象那些成员直接隶属于内部 

类对象一样。这样便为回调问题提供了一个更优秀的方案——C++是用指向成员的指针解决的。  

(29) 由于存在前面介绍的那种内部类,所以Java 里没有指向成员的指针。  

(30) Java不存在“嵌入”(inline)方法。Java 编译器也许会自行决定嵌入一个方法,但我们对此没有更 

多的控制权力。在Java 中,可为一个方法使用 final 关键字,从而“建议”进行嵌入操作。然而,嵌入函数 

对于C++的编译器来说也只是一种建议。  

(31) Java 中的继承具有与C++相同的效果,但采用的语法不同。Java 用 extends 关键字标志从一个基础类 

的继承,并用super 关键字指出准备在基础类中调用的方法,它与我们当前所在的方法具有相同的名字(然 

而,Java 中的super 关键字只允许我们访问父类的方法——亦即分级结构的上一级)。通过在 C++中设定基 

础类的作用域,我们可访问位于分级结构较深处的方法。亦可用 super 关键字调用基础类构建器。正如早先 

指出的那样,所有类最终都会从Object 里自动继承。和C++不同,不存在明确的构建器初始化列表。但编译 

器会强迫我们在构建器主体的开头进行全部的基础类初始化,而且不允许我们在主体的后面部分进行这一工 

作。通过组合运用自动初始化以及来自未初始化对象句柄的异常,成员的初始化可得到有效的保证。  

  

public class Foo extends Bar {  

  public Foo(String msg) {  

    super(msg); // Calls base constructor  

  }  

  public baz(int i) { // Override  

    super。baz(i); // Calls base method  

  }  

}  

  

(32) Java 中的继承不会改变基础类成员的保护级别。我们不能在Java 中指定public,private 或者 

protected 继承,这一点与C++是相同的。此外,在衍生类中的优先方法不能减少对基础类方法的访问。例 

如,假设一个成员在基础类中属于 public,而我们用另一个方法代替了它,那么用于替换的方法也必须属于 

public (编译器会自动检查)。  

(33) Java提供了一个 interface 关键字,它的作用是创建抽象基础类的一个等价物。在其中填充抽象方 

法,且没有数据成员。这样一来,对于仅仅设计成一个接口的东西,以及对于用 extends 关键字在现有功能 

基础上的扩展,两者之间便产生了一个明显的差异。不值得用 abstract 关键字产生一种类似的效果,因为我 

们不能创建属于那个类的一个对象。一个 abstract (抽象)类可包含抽象方法(尽管并不要求在它里面包含 

什么东西),但它也能包含用于具体实现的代码。因此,它被限制成一个单一的继承。通过与接口联合使 

用,这一方案避免了对类似于 C++虚拟基础类那样的一些机制的需要。  

为创建可进行“例示”(即创建一个实例)的一个 interface (接口)的版本,需使用implements 关键字。 

它的语法类似于继承的语法,如下所示:  



                                                                       674 


…………………………………………………………Page 676……………………………………………………………

  

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