Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
- [x] [附录:数据压缩](docs/book/Appendix-Data-Compression.md)
- [ ] [附录:对象序列化](docs/book/Appendix-Object-Serialization.md)
- [ ] [附录:静态语言类型检查](docs/book/Appendix-Benefits-and-Costs-of-Static-Type-Checking.md)
- [x] [附录:C++和Java的优良传统](docs/book/Appendix-The-Positive-Legacy-of-C-plus-plus-and-Java.md)
- [ ] [附录:成为一名程序员](docs/book/Appendix-Becoming-a-Programmer.md)


Expand Down
11 changes: 8 additions & 3 deletions docs/book/12-Collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ Braeburn@4e25154f

因此,可以将 **Apple** 的子类型添加到被指定为保存 **Apple** 对象的集合中。

程序的输出是从 **Object** 默认的 **toString()** 方法产生的,该方法打印类名,后边跟着对象的散列码的无符号十六进制表示(这个散列码是通过 **hashCode()** 方法产生的)。将在[附录:理解equals和hashcode方法]()中了解有关散列码的内容。
程序的输出是从 **Object** 默认的 **toString()** 方法产生的,该方法打印类名,后边跟着对象的散列码的无符号十六进制表示(这个散列码是通过 **hashCode()** 方法产生的)。将在[附录:理解equals和hashCode方法]()中了解有关散列码的内容。

<!-- Basic Concepts -->
## 基本概念
Expand Down Expand Up @@ -1789,13 +1789,18 @@ Serializable]

尽管存在这些问题,但Java集合仍是在日常工作中使用的基本工具,它可以使程序更简洁、更强大、更有效。你可能需要一段时间才能熟悉集合类库的某些方面,但我想你很快就会找到自己的路子,来获得和使用这个类库中的类。

[^1]: 许多语言,例如Perl,Python和Ruby,都有
集合的本地支持。
[^1]: 许多语言,例如Perl,Python和Ruby,都有集合的本地支持。

[^2]: 这里是操作符重载的用武之地,C++和C#的集合类都使用操作符重载生成了更简洁的语法。

[^3]: 在[泛型]()章节的末尾,有个关于这个问题是否很严重的讨论。但是,[泛型]()章节还将展示Java泛型远不止是类型安全的集合这么简单。

[^4]: **remove()** 是一个所谓的“可选”方法(还有一些其它的这种方法),这意味着并非所有的 **Iterator** 实现都必须实现该方法。这个问题将在[附录:集合主题]()中介绍。但是,标准Java库集合实现了 **remove()** ,因此在[附录:集合主题]()章节之前,都不必担心这个问题。

[^5]: 这实际上依赖于具体实现。优先级队列算法通常会按插入顺序排序(维护一个*堆*),但它们也可以在删除时选择最重要的元素。 如果对象的优先级在它在队列中等待时可以修改,那么算法的选择就显得很重要了。

[^6]: 有些人提倡这样一种自动创建机制,即对一个类中所有可能的方法组合都自动创建一个接口,有时候对于单个的类都是如此。 我相信接口的意义不应该仅限于方法组合的机械地复制,因此我在创建接口之前,总是要先看到增加接口带来的价值。

[^7]: 这在Java SE5之前是不可用的,因为该方法被认为与操作系统的耦合度过紧,因此违反“一次编写,处处运行”的原则。现在提供它这一事实表明,Java的设计者们更加务实了。

<!-- 分页 -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,29 @@
<!-- Appendix: The Positive Legacy of C++ and Java -->
# 附录:C++和Java的优良传统

> 在各种讨论声中,有一些人认为C++是一种设计糟糕的语言。 我认为理解C++和Java语言的选择有助于了解更大的视角。

也就是说,我几乎不再使用C++了。当我使用它的时候,要么是用来检查遗留代码,要么是编写性能关键(performance-critical)部分,程序通常尽可能小,以便用其他语言编写的其他程序来调用。

因为我在最初的8年里一直在C++标准委员会工作,所以我见证了那些被做出的决定。它们都经过了极其谨慎的考虑,远远超过了许多在Java中做出的决定。

然而,正如人们正确地指出的那样,由此产生的语言使用起来既复杂又痛苦,而且只要我一段时间不使用它,我就会忘记那些古怪的规则。在我写书的时候,我是从第一原理(first principles)处了解这些规则的,而不是记住了它们。

为了理解C++语言为何既令人不愉快且复杂,同时又是精心设计的,必须要牢记C++中所有内容的主要设计决策:与C. Bjarne Stroustrup(该语言的创造者,即“C++之父”)的兼容性决定。这样的设计似乎是为了可以让大量的C程序员透明地转移到对象(代指C++)上:允许他们在C++下编译他们的C代码。这是一个巨大的限制,一直是C++最大的优势......而且也是它的祸根。这就是使得C++成功的原因,也是使它复杂的原因。

它也欺骗了那些不太了解C++的Java设计师。例如,他们认为运算符重载对于程序员来说很难正确使用。这在C++中基本上是正确的,因为C++既有栈分配又有堆分配,你必须重载运算符来处理所有情况而且不要造成内存泄漏。这确实很困难。然而,Java有单一的内存分配机制和一个垃圾收集器,这使得运算符重载变得微不足道,正如C#中那样(但在早于Java的Python中已经可以看到)。但多年来,来自Java团队的一贯态度是“运算符重载太复杂了”。这里还有许多决策,所做的事明显不应该是他们做的。正是由于这些原因,让我有了蔑视Gosling(即“Java之父”)和Java团队决策的名声。(Java 7和8由于某种原因包含了更好的决策。但是向后兼容性这个约束总是会阻碍真正的改进。语言永远不会是它本来的样子。)

还有很多其他的例子。“为了提高效率,必须包含基本类型”;坚持“万物皆对象”是正确的;当对性能有要求的时候,提供一个陷阱门(trap door)来做低级别的活动(lower-level activities)(这里也可以使用hotspot技术透明地提高性能,正如他们最终做的那样);不能直接使用浮点处理器去计算超越函数,它用软件来完成。我已经尽可能多地提出了这样的问题,但我得到的却一直是类似“这是Java方式”这样的回复。

当我提出关于泛型的设计有多糟糕的时候,我得到了相同的回复,以及“我们必须向后兼容那样以前用Java做出的决策”(即使它们是糟糕的决策)。最近越来越多的人已经获得了足够的泛型经验,可以发现泛型真的很难用。事实上,C++模板更强大、更一致(现在更容易使用,因为编译器的错误消息是可以容忍的)。人们一直在认真对待物化(reification),这可能是有用的东西,但是在那种被严格约束所削弱的设计中并没有多大影响。

这样的例子还有很多很多。这是否意味着Java失败了?绝对不。Java将程序员的主流带入了垃圾收集、虚拟机和一致的错误处理模型的世界。由于它的所有缺陷,它将我们提升到了一个水平,现在我们已经准备好使用更高级别的语言了。

有一点,C++是领先的语言,人们认为它总是如此。许多人对Java有同样的看法,但由于JVM,Java使得取代自己变得更加容易。现在有可能会有人创建一种新语言,并使其在短时间内像Java一样高效运行。以前,为新语言开发一个正确有效的编译器需要花费大部分开发时间。

这种情况已经发生了,包括像Scala这样的高级静态语言,以及动态语言,新的且可移植的,如Groovy,Clojure,JRuby和Jython。这是未来,并且过渡很顺畅,因为可以很轻易地将这些新语言与现有Java代码结合使用,并且必要时可以重写那些在Java中的瓶颈。

在撰写本文时,Java是世界上的头号编程语言。然而,Java最终将会减弱,就像C++一样,沦只在特殊情况下使用(或者只是用来支持传统的代码,因为它不能像C++那样和硬件连接)。但是无意中的好处,也是Java真正意外的光彩之处在于它为自己的替代品创造了一条非常畅通的道路,即使Java本身已经达到了无法再发展的程度。未来所有的语言都应该从中学习:要么创建一个可以重构的文化(像Python和Ruby做的那样),要么就让竞争者茁壮成长。

<!-- 分页 -->
<div style="page-break-after: always;"></div>