diff --git a/docs/book/08-Reuse.md b/docs/book/08-Reuse.md index 729d4ca..e10f875 100644 --- a/docs/book/08-Reuse.md +++ b/docs/book/08-Reuse.md @@ -1176,12 +1176,14 @@ public class Jurassic { 但请留意你的假设。通常来说,预见一个类如何被复用是很困难的,特别是通用类。如果将一个方法指定为 **final**,可能会防止其他程序员的项目中通过继承来复用你的类,而这仅仅是因为你没有想到它被以那种方式使用。 -Java 标准类库就是一个很好的例子。尤其是 Java 1.0/1.1 的 **Vector** 类被广泛地使用,如果它的所有方法没有因为从效率考虑(这近乎是个幻想),而被指定为 **final**,可能会更加有用。很容易想到,你可能会继承并覆写这么一个基础类,但是设计者们认为这么做不合适。有两个讽刺的原因。第一,**Stack** 继承自 **Vector**,就是说 **Stack** 是个 **Vector**,但从逻辑上来说不对。尽管如此,Java 设计者们仍然这么做,在用这种方式创建 **Stack** 时,他们应该意识到了 **final** 方法过于约束。 +Java 标准类库就是一个很好的例子。尤其是 Java 1.0/1.1 的 **Vector** 类被广泛地使用,然而它的所有方法出于"效率"考虑(然而并没有提升效率,只是幻觉)全被指定为 **final** ,如果不指定 **final** 的话,可能会更加有用[^1]。很容易想到,你可能会继承并覆写这么一个基础类,但是设计者们认为这么做不合适。有两个讽刺的原因。第一,**Stack** 继承自 **Vector**,就是说 **Stack** 是个 **Vector**,但从逻辑上来说不对。尽管如此,Java 设计者们仍然这么做,在用这种方式创建 **Stack** 时,他们应该意识到了 **final** 方法过于约束。 第二,**Vector** 中的很多重要方法,比如 `addElement()` 和 `elementAt()` 方法都是同步的。在“并发编程”一章中会看到同步会导致很大的执行开销,可能会抹煞 **final** 带来的好处。这加强了程序员永远无法正确猜到优化应该发生在何处的观点。如此笨拙的设计却出现在每个人都要使用的标准库中,太糟糕了。庆幸的是,现代 Java 容器用 **ArrayList** 代替了 **Vector**,它的行为要合理得多。不幸的是,仍然有很多新代码使用旧的集合类库,其中就包括 **Vector**。 Java 1.0/1.1 标准类库中另一个重要的类是 **Hashtable**(后来被 **HashMap** 取代),它不含任何 **final** 方法。本书中其他地方也提到,很明显不同的类是由不同的人设计的。**Hashtable** 就比 **Vector** 中的方法名简洁得多,这又是一条证据。对于类库的使用者来说,这是一个本不应该如此草率的事情。这种不规则的情况造成用户需要做更多的工作——这是对粗糙的设计和代码的又一讽刺。 +- **[1]** Java 1.4 开始已将 **Vector** 类大多数方法的 **final** 去掉 + ## 类初始化和加载 diff --git a/docs/book/10-Interfaces.md b/docs/book/10-Interfaces.md index f2bc527..7eb5cf4 100644 --- a/docs/book/10-Interfaces.md +++ b/docs/book/10-Interfaces.md @@ -104,7 +104,7 @@ public class Instantiable extends Uninstantiable { } ``` -留意 `@Override` 的使用。没有这个注解的话,如果你没有定义相同的方法名或签名,抽象机制会认为你没有实现抽象方法从而产生编译时错误。因此,你可能认为这里的 `@Override` 是多余的。但是,`@Override` 还提示了这个方法被覆写——我认为这是有用的,所以我会使用 `@Override`,即使在没有这个注解,编译器告诉我错误的时候。 +留意 `@Override` 的使用。没有这个注解的话,如果你没有定义相同的方法名或签名,抽象机制会认为你没有实现抽象方法从而产生编译时错误。因此,你可能认为这里的 `@Override` 是多余的。但是,`@Override` 还提示了这个方法被覆写——我认为这是有用的,所以我会使用 `@Override`,不仅仅是因为当没有这个注解时,编译器会告诉我出错。 记住,事实上的访问权限是“friendly”。你很快会看到接口自动将其方法指明为 **public**。事实上,接口只允许 **public** 方法,如果不加访问修饰符的话,接口的方法不是 **friendly** 而是 **public**。然而,抽象类允许每件事: