保持最小的可变性
说一个类"不变",就是说它的所有对象在运行时不可以被更改。Java系统库中有很多这样的例子,比如String、类封装的基本数据类型、BigInteger和BigDecimal等等。想创建一个不变类,需要遵循下面5条原则:
1. 不能提供任何改变对象状态的方法(比如setter)。
2. 保证类不能被继承,否则子类将可以通过覆盖父类方法来改变对象状态。常用的做法是把类声明为final,还有另一种方法是隐藏或保护所有的构造函数,只提供一个静态factory方法来创建对象(参见item 1)。
3. 所有属性都声明为final。
4. 所有属性都声明为私有。

又是很简单的一节

public类不应该有public属性,必须使用访问方法(accessor methods)

有些情况下,会需要写一些纯粹用作数据存储,而没有任何行为的类,比如:

// Degenerate classes like this should not be public!
class Point {
	public double x;
	public double y;
}

上一节所说,这样做会破坏数据封装,所以Object-Oriented语言的死忠分子们会拒绝接受这样的写法,并要求全面使用访问方法改写它:

这节比较简单,都是各种面试考烂了的东西。

类和属性的访问控制应尽可能严格

访问控制是Java语言中最重要的概念之一,它使得对数据的封装成为可能。好的数据封装可以有效分隔一个系统中的不同模块,增加系统可靠性,便于维护,而且使各模块的开发和重构完全独立,实现细节上的改动不会影响对外开放的API。

对于类,有两个访问级别:package-private和public。其中前者是默认的,如果一个类没有被声明为public,那么它就是package-private,也就是说,它只在其自己所在的软件包内可见。这两个级别的选择没什么复杂的:只有要作为API开放的类,才声明为public,其余实现的细节,则尽可能都声明为package-private。如果一个非public类只被另外一个类使用,那么它应该被定义成使用者的私有内嵌类(private nested class),这样可以进一步减小它的可见范围,使其更好地被保护。

前一阵子准备雅思考试,没时间继续Effective Java,现在考完了,要捡起来。

实现Comparable接口

Comparable接口只有唯一一个方法:

public interface Comparable<T> {
	int compareTo(T t);
}

compareTo方法的返回值是一个整数。对于a.compareTo(b),如果返回负值,则表明a < b;正值表明a > b;如果返回0,则说明a与b相等。如果a与b类型不同,应该弹出ClassCastException。

好艰深的一节,看了两三遍才完全吃透。

覆盖clone方法要谨慎

Java中一个广为人知的复制对象的方法是clone。这个方法看上去方便好用,但实际上问题和限制都很多,所以不推荐使用。需要复制对象的情况下,应该尽可能使用复制构造函数或静态factory方法。

clone方法最大的问题来自于它的实现机制:Cloneable接口。这个接口严重破坏了Java语言中接口的使用规范,所以被称为"extralinguistic"。通常情况下,一个接口需要声明一些方法,而实现接口的类必须覆盖这些方法以提供具体行为。这样的覆盖是强制性的,否则会产生编译错误。但Cloneable接口是一个特例,它没有声明任何方法,实际上是一个空接口,因而实现它的类不会被强制覆盖clone方法。此接口的唯一作用,是作为一个"开关",用来开放Object类中的clone方法。

任何情况下toString方法都应该被覆盖

java.lang.Object已经提供了一个默认的toString方法,它的返回值,是"[类名]@[对象的hash]",比如:"PhoneNumber@163b91"。这样的信息,显然不太有用。所以语言规范中建议开发者在所有Object的子类中都覆盖toString方法,以返回明确易读的关于对象的信息。

在覆盖toString方法时,应该返回关于对象的所有有用信息。如果对象中信息量巨大,那么应该返回一个概要。比如上面电话号码的例子,可以返回类似于"(707) 867-5309"的结果;而对于"曼哈顿黄页"这样的对象,可以返回"Manhattan white pages (1487536 listings)",而不是把所有的listing都列出来。

关于返回值的格式,可以在注释中以规范的形式公布,并且提供一个factory或者构造函数,让开发者可以方便地在对象和它的字符串表示之间转换。这样做的坏处是,一旦规范公布,并且类型被大量使用,之后就很难对其进行修改,因为那将破坏用户端代码。不管toString格式是否提供规范,都应该在注释中说明,比如下面是为item 9中PhoneNumber类定义的toString方法:

第2页 共4页