mirror of
https://github.com/LingCoder/OnJava8.git
synced 2026-09-06 06:45:05 +08:00
优化docify排版展示
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
这句话无论对于自然语言还是编程语言来说都是一样的。你所使用的编程语言会将你的思维模式固化并逐渐远离其他语言,而且往往发生在不知不觉中。Java 作为一门傲娇的语言尤其如此。
|
||||
|
||||
Java是一门派生语言,早期语言设计者为了不想在项目中使用 C++ 而创造了这种看起来很像 C++,却比 C++ 有了改进的新语言(他们原始的项目到最后也没有实现)。Java最核心的变化就是加入了“虚拟机”和“垃圾回收机制”,这两个概念在本书之后的章节会有详细描述。 此外,Java 还在其他方面推动行业了发展,例如,现在绝大多数编程语言都包含文档注释语法和 HTML 文档生成的工具。
|
||||
Java 是一门派生语言,早期语言设计者为了不想在项目中使用 C++ 而创造了这种看起来很像 C++,却比 C++ 有了改进的新语言(他们原始的项目到最后也没有实现)。Java 最核心的变化就是加入了“虚拟机”和“垃圾回收机制”,这两个概念在本书之后的章节会有详细描述。 此外,Java 还在其他方面推动行业了发展,例如,现在绝大多数编程语言都包含文档注释语法和 HTML 文档生成的工具。
|
||||
|
||||
Java 最主要的概念之一“对象”来自 SmallTalk 语言。SmallTalk 语言坚定不移的认为“对象”(在下一章中描述)是编程的最基本单元,于是,万物皆对象。时间已经检验了这种信念,并发现它太过狂热,有些人甚至认为“对象”是完全错误的概念,应该被丢弃。就我个人而言,把一切都当成一个对象不仅是一项不必要的负担,而且还会招致许多设计朝着不好的方向发展。尽管如此,“对象”的概念依然有其闪光点。固执地要求所有东西都是一个对象(特别是一直到最底层级别)是一个设计错误,相反,完全逃避“对象”的概念似乎同样太过苛刻。
|
||||
|
||||
@@ -49,7 +49,7 @@ Java 最主要的概念之一“对象”来自 SmallTalk 语言。SmallTalk 语
|
||||
|
||||
## C编程思想
|
||||
|
||||
*Thinking in C* 已经可以在 www.OnJava8.com 免费下载。Java 的基础语法是基于 C 语言的。*Thinking in C* 中有更适合初学者的编程基础介绍。 我已经委托 Chuck Allison 将这本 C 基础的书籍作为独立产品附赠于本书的 CD 中。希望大家在阅读本书时,都已具备了学习 JAVA 的良好基础。
|
||||
*Thinking in C* 已经可以在 www.OnJava8.com 免费下载。Java 的基础语法是基于 C 语言的。*Thinking in C* 中有更适合初学者的编程基础介绍。 我已经委托 Chuck Allison 将这本 C 基础的书籍作为独立产品附赠于本书的 CD 中。希望大家在阅读本书时,都已具备了学习 Java 的良好基础。
|
||||
|
||||
|
||||
## 源码下载
|
||||
@@ -99,9 +99,9 @@ Java 在图形用户界面和桌面程序方面的发展可以说是一段悲伤
|
||||
|
||||
在 Java 1.1 版本的AWT中 情况有所改善,事件模型采用了更加清晰的面向对象方法,并添加了JavaBeans,致力于面向易于创建可视化编程环境的组件编程模型(已废弃)。
|
||||
|
||||
Java 2(Java 1.2)通过基本上用 Java 基类(JFC)替换所有内容来完成从旧 Java 1.0 AWT的转换,其中 GUI 部分称为 “Swing”。这是一组丰富的JavaBeans,它们创建了一个合理的GUI。修订版 3(3之前都不好)比以往更适用于开发图形界面程序。
|
||||
Java 2(Java 1.2)通过基本上用 Java 基类(JFC)替换所有内容来完成从旧 Java 1.0 AWT的转换,其中 GUI 部分称为 “Swing”。这是一组丰富的 JavaBeans,它们创建了一个合理的GUI。修订版 3(3之前都不好)比以往更适用于开发图形界面程序。
|
||||
|
||||
Sun 在图形界面的最后一次尝试,称为 JavaFX。当 Oracle 收购 Sun 时,他们将原来雄心勃勃的项目(包括脚本语言)改为库,现在它似乎是 Java 官方唯一还在开发中的UI工具包(参见维基百科关于JavaFX 的文章) - 但即使如此。JavaFX 似乎最终后也失败了。
|
||||
Sun 在图形界面的最后一次尝试,称为 JavaFX。当 Oracle 收购 Sun 时,他们将原来雄心勃勃的项目(包括脚本语言)改为库,现在它似乎是 Java 官方唯一还在开发中的UI工具包(参见维基百科关于 JavaFX 的文章) - 但即使如此。JavaFX 似乎最终后也失败了。
|
||||
|
||||
现今 Swing 依然是 Java 发行版的一部分(只接受维护,不再有新功能开发),而 Java 现在是一个开源项目,它应该始终可用。此外,Swing 和 JavaFX 有一些有限的交互性。这些可能是为了帮助开发者过渡到 JavaFX。
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# 前言
|
||||
|
||||
> 本书基于 Java 8 版本来教授当前 JAVA 编程的最优实践。
|
||||
> 本书基于 Java 8 版本来教授当前 Java 编程的最优实践。
|
||||
|
||||
在此之前,我的另一本 Java 书籍 Thinking in Java 第 4 版(《Java编程思想》 Prentice Hall 2006)对于 Java 5的编程依然有指导意义。Java 5 是用于 Android 编程的语言版本。
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
## 教学目标
|
||||
|
||||
每章教授一个或一组相关的概念,并且这些知识不依赖于尚未学习到的章节。这样以来,学习者可以在当前知识的背景框架下循序渐进地掌握 JAVA。
|
||||
每章教授一个或一组相关的概念,并且这些知识不依赖于尚未学习到的章节。这样以来,学习者可以在当前知识的背景框架下循序渐进地掌握 Java。
|
||||
|
||||
本书的教学目标:
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
诺贝尔经济学奖得主约瑟夫·斯蒂格利茨(Joseph Stiglitz)有一套适用于这里的人生哲学,叫做“承诺升级理论”:继续犯错误的成本由别人承担,而承认错误的成本由自己承担。
|
||||
|
||||
如果你有读过我过去的作品,那么你应该知道,我一般倾向于指出这些语言设计错误。Java 已经发展出了一批狂热的追随者,他们对待这门语言更像是阵营而不是编程工具。因为我已经写过有关 Java 的书,所以他们理所当然的认为我也是这个“阵营”的一份子。于是,当我指出Java的错误时,就会造成两种影响:
|
||||
如果你有读过我过去的作品,那么你应该知道,我一般倾向于指出这些语言设计错误。Java 已经发展出了一批狂热的追随者,他们对待这门语言更像是阵营而不是编程工具。因为我已经写过有关 Java 的书,所以他们理所当然的认为我也是这个“阵营”的一份子。于是,当我指出 Java 的错误时,就会造成两种影响:
|
||||
|
||||
1. 最初,会有许多错误“阵营”的人成为了牺牲品。最终,时隔多年,大家都意识到这是个设计上的错误,然后错误就这样成为了 Java 历史的一部分。
|
||||
|
||||
@@ -44,13 +44,13 @@
|
||||
|
||||
已知的语言设计错误也会给新的一门编程语言的发明提供参考意义。探索一门语言能做什么是很有趣的一件事,而语言设计错误能提醒你哪些“坑”是不能再趟的。多年以来,我一直感觉 Java 的设计者们有点脱离群众的。Java 有些设计错误不免错的太明显,我都怀疑语言设计师们到底是为了用户服务还是出于其他的动机设计了这些功能。Java 语言有许多臭名昭著的设计错误,很可能这也是诱惑所在。我感觉这是对程序员的不尊重。为此我很长时间不想于 Java 有任何瓜葛,很大程度上,这也是我为什么不想碰 Java的原因吧。
|
||||
|
||||
现今当我再来看 Java 8时,我发现与之前有许多不同的地方。Java 语言的设计师们似乎对于语言和用户的态度发生了根本性上的改变。在多年忽视用户投诉之后,许多功能和库已经被语言搞砸了。
|
||||
现今当我再来看 Java 8 时,我发现与之前有许多不同的地方。Java 语言的设计师们似乎对于语言和用户的态度发生了根本性上的改变。在多年忽视用户投诉之后,许多功能和库已经被语言搞砸了。
|
||||
|
||||
新功能的设计与以往有很大不同。掌舵者开始重视程序员的编程经验。新功能最终都在努力使语言变得更好,而不仅仅是停留在快速添加想法而不深入研究它们的含义。有一些新功能实现上非常优雅(至少在 Java 约束下尽可能优雅)。
|
||||
|
||||
我猜测可能是一些人离开设计组让他们意识到了这点。我没想到会有这些变化!因为这些原因吧,写这本书的体验要比以往的经历要好得多。Java 8 包含了一系列基础和重要的改进。哎,不过 Java有严格的“向后兼容”承诺。所以可能我们不大可能看到戏剧性的变化,当然我希望我是错的。尽管如此,我很赞赏那些敢于自我颠覆,并为 Java设定更好路线的人。第一次,对于自己所写的部分 Java 8代码我终于可以说“我喜欢这个!”
|
||||
我猜测可能是一些人离开设计组让他们意识到了这点。我没想到会有这些变化!因为这些原因吧,写这本书的体验要比以往的经历要好得多。Java 8 包含了一系列基础和重要的改进。哎,不过 Java 有严格的“向后兼容”承诺。所以可能我们不大可能看到戏剧性的变化,当然我希望我是错的。尽管如此,我很赞赏那些敢于自我颠覆,并为 Java 设定更好路线的人。第一次,对于自己所写的部分 Java 8 代码我终于可以说“我喜欢这个!”
|
||||
|
||||
最后,本书所著时间似乎也很不错,因为 Java 8 引入的新功能已经强烈的影响了今后Java的编码方式。截止我在写这本书时,Java 9似乎更专注于对语言底层的基础结构功能的重要更新,但是这些并不会影响本书所关注的编码类型。话说回来,得益于电子书出版形式的便捷,如果我发现本书有需要更新或添加的内容,我可以很快将新版本推送给现有读者。
|
||||
最后,本书所著时间似乎也很不错,因为 Java 8 引入的新功能已经强烈的影响了今后 Java 的编码方式。截止我在写这本书时,Java 9 似乎更专注于对语言底层的基础结构功能的重要更新,但是这些并不会影响本书所关注的编码类型。话说回来,得益于电子书出版形式的便捷,如果我发现本书有需要更新或添加的内容,我可以很快将新版本推送给现有读者。
|
||||
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ Java 的普及性对于其受欢迎程度有重要意义。学习 Java 会让你
|
||||
|
||||
## 关于安卓
|
||||
|
||||
这本书基于 Java 8 版本。如果你是 Andriod 程序员,请务必学习 Java 5。在《On Java 8》出版的时候,我的另一本基于 Java 5的著作 Thinking in Java 4th Edition(《Java编程思想》第四版)已经可以在[www.OnJava8.com](http://www.OnJava8.com)上免费下载了。此外,还有许多其他专用于 Andriod 编程的资源。
|
||||
这本书基于 Java 8 版本。如果你是 Andriod 程序员,请务必学习 Java 5。在《On Java 8》出版的时候,我的另一本基于 Java 5 的著作 Thinking in Java 4th Edition(《Java编程思想》第四版)已经可以在[www.OnJava8.com](http://www.OnJava8.com)上免费下载了。此外,还有许多其他专用于 Andriod 编程的资源。
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -247,9 +247,9 @@ Java 的单继承结构有很多好处。由于所有对象都有继承自一个
|
||||
|
||||
2. 不同的集合种类对应着不同的用途。例如,List 的两种基本类型:ArrayList 和 LinkedList。虽然两者具有相同接口和外部行为,但是在某些操作中它们的效率差别很大。在 ArrayList 中随机查找元素是很高效的,而 LinkedList 随机查找效率低下。反之,在 LinkedList 中插入元素的效率要比在 ArrayList 中高。由于底层数据结构的不同,每种集合类型在执行相同的操作时会表现出效率上的差异。
|
||||
|
||||
通过对 List 接口的抽象,我们可以很容易的将 LinkedList 改为 ArrayList。在 Java 5泛型出来之前,集合中保存的是通用类型 `Object`。Java 单继承的结构意味着所有元素都基于 `Object` 类,所以在集合中可以保存任何类型的数据。这也使得集合易于重用。要使用这样的集合时,我们先要往集合添加元素。由于 Java 5版本前的集合只保存 `Object`,当我们往集合中添加元素时,元素便向上转型成了 `Object`,从而丢失自己原有的类型特性。这时我们再从对象中取出该元素时,元素的类型变成了 `Object`。那么我们该怎么将其转回原先具体的类型的?这里,我们使用了强制类型转换将其转为更具体的类型。这个过程称之为对象的“向下转型”。通过“向上转型”,我们知道“圆形”也是一种“形状”,这个过程是安全的。可是我们不能从“Object”看出其就是“圆圈”或“形状”,所以除非我们能确定元素的具体类型信息,否则“向下转型”就是不安全的。也不能说这样的错误就时完全危险的,因为一旦我们转化了错误的类型,程序就会运行出错,抛出“运行时异常”(*RuntimeException*)。(后面的章节会提到) 无论如何,我们要寻找一种在取出集合元素时确定其具体类型的方法。另外,每次取出元素都要做额外的“向下转型”对程序和程序员都是一种开销。以某种方式创建集合,以确认保存元素的具体类型,减少集合元素“向下转型”中的开销和可能出现的错误难道不好吗?这种解决方案就是:参数化类型机制(*Parameterized Type Mechanism*)。
|
||||
通过对 List 接口的抽象,我们可以很容易的将 LinkedList 改为 ArrayList。在 Java 5 泛型出来之前,集合中保存的是通用类型 `Object`。Java 单继承的结构意味着所有元素都基于 `Object` 类,所以在集合中可以保存任何类型的数据。这也使得集合易于重用。要使用这样的集合时,我们先要往集合添加元素。由于 Java 5 版本前的集合只保存 `Object`,当我们往集合中添加元素时,元素便向上转型成了 `Object`,从而丢失自己原有的类型特性。这时我们再从对象中取出该元素时,元素的类型变成了 `Object`。那么我们该怎么将其转回原先具体的类型的?这里,我们使用了强制类型转换将其转为更具体的类型。这个过程称之为对象的“向下转型”。通过“向上转型”,我们知道“圆形”也是一种“形状”,这个过程是安全的。可是我们不能从“Object”看出其就是“圆圈”或“形状”,所以除非我们能确定元素的具体类型信息,否则“向下转型”就是不安全的。也不能说这样的错误就时完全危险的,因为一旦我们转化了错误的类型,程序就会运行出错,抛出“运行时异常”(*RuntimeException*)。(后面的章节会提到) 无论如何,我们要寻找一种在取出集合元素时确定其具体类型的方法。另外,每次取出元素都要做额外的“向下转型”对程序和程序员都是一种开销。以某种方式创建集合,以确认保存元素的具体类型,减少集合元素“向下转型”中的开销和可能出现的错误难道不好吗?这种解决方案就是:参数化类型机制(*Parameterized Type Mechanism*)。
|
||||
|
||||
参数化类型机制可以使得编译器能够自动识别某个 `class` 的具体类型并正确地执行. 举个例子,对集合的参数化类型机制可以让其仅接受“形状”这种类型的元素,并以“形状”类型取出元素。Java 5版本支持了参数化类型机制,称之为“泛型”(*Generic*)。泛型是 Java 5的主要特性之一。举个例子,你可以按以下方式向 ArrayList 种添加 Shape(形状):
|
||||
参数化类型机制可以使得编译器能够自动识别某个 `class` 的具体类型并正确地执行. 举个例子,对集合的参数化类型机制可以让其仅接受“形状”这种类型的元素,并以“形状”类型取出元素。Java 5 版本支持了参数化类型机制,称之为“泛型”(*Generic*)。泛型是 Java 5 的主要特性之一。举个例子,你可以按以下方式向 ArrayList 种添加 Shape(形状):
|
||||
|
||||
```java
|
||||
ArrayList<Shape> shapes = new ArrayList<>();
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
尽管和现在的图形用户界面相比,Shell 操作方式很原始。但是同时 shell 也为我们提供了许多有用的功特性。在学习本书的过程中,我们会经常使用到 Shell,包括现在这部分的安装,还有运行 Java 程序。
|
||||
|
||||
Mac:单击聚光灯(屏幕右上角的放大镜图标),然后键入“terminal”。单击看起来像小电视屏幕的应用程序(您也可以单击“return”)。这就启动了你的用户下的 shell窗口。
|
||||
Mac:单击聚光灯(屏幕右上角的放大镜图标),然后键入“terminal”。单击看起来像小电视屏幕的应用程序(您也可以单击“return”)。这就启动了你的用户下的 shell 窗口。
|
||||
|
||||
windows:首先,通过目录打开 windows 资源管理器:
|
||||
Windows 7: 单击屏幕左下角的“开始”图标,输入“explorer”后按回车键。
|
||||
@@ -42,7 +42,7 @@ Mac:单击聚光灯(屏幕右上角的放大镜图标),然后键入“te
|
||||
**Shell基本操作**
|
||||
我在这展示的 Shell 操作和系统中大体相同。出于本书的原因,下面列举一些在 Shell 中的基本操作:
|
||||
|
||||
```shell
|
||||
```bash
|
||||
更改目录: cd <路径>
|
||||
cd .. 移动到上级目录
|
||||
pushd <路径> 记住来源的同时移动到其他目录,popd 返回上一个目录
|
||||
@@ -81,7 +81,7 @@ Mac:单击聚光灯(屏幕右上角的放大镜图标),然后键入“te
|
||||
Linux/Mac 都有命令行解压程序,您可以通过互联网为Windows安装命令行解压程序。
|
||||
图形界面下(Windows 资源管理器、Mac Finder ,Linux Nautilus 或其他等效软件)右键单击该文件,
|
||||
在 Mac 上选择“open”,在 Linux 上选择“extract here”,或在 Windows 上选择“extract all…”。
|
||||
要了解关于shell 的更多信息,请在维基百科中搜索 Windows shell,Mac/Linux用户可搜索 bash shell。
|
||||
要了解关于 shell 的更多信息,请在维基百科中搜索 Windows shell,Mac/Linux用户可搜索 bash shell。
|
||||
|
||||
```
|
||||
|
||||
@@ -96,7 +96,7 @@ Mac:单击聚光灯(屏幕右上角的放大镜图标),然后键入“te
|
||||
1. 以下为 Chocolatey 的[安装说明](https://chocolatey.org/)。
|
||||
2. 在命令行提示符下输入下面的命令,等待片刻,结束后 Java 安装完成并自动完成环境变量设置。
|
||||
|
||||
```shell
|
||||
```bash
|
||||
choco install jdk8`.
|
||||
```
|
||||
|
||||
@@ -106,7 +106,7 @@ Mac 系统自带的 Java 版本太老,为了确保本书的代码示例能被
|
||||
1. 以下为 HomeBrew 的[安装说明](https://brew.sh/)。安装完成后执行命令 `brew update` 更新到最新版本
|
||||
2. 在命令行下执行下面的命令来安装 Java。
|
||||
|
||||
```shell
|
||||
```bash
|
||||
brew cask install java
|
||||
```
|
||||
|
||||
@@ -116,13 +116,13 @@ Mac 系统自带的 Java 版本太老,为了确保本书的代码示例能被
|
||||
|
||||
* **Ubuntu/Debian**:
|
||||
|
||||
```shell
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install default-jdk
|
||||
```
|
||||
* **Fedora/Redhat**:
|
||||
|
||||
```shell
|
||||
```bash
|
||||
su-c "yum install java-1.8.0-openjdk"
|
||||
```
|
||||
|
||||
@@ -131,13 +131,13 @@ Mac 系统自带的 Java 版本太老,为了确保本书的代码示例能被
|
||||
|
||||
打开新的命令行输入:
|
||||
|
||||
```shell
|
||||
```bash
|
||||
java -version
|
||||
```
|
||||
|
||||
正常情况下 你应该看到以下类似信息(版本号信息可能不一样):
|
||||
|
||||
```shell
|
||||
```bash
|
||||
java version "1.8.0_112"
|
||||
Java(TM) SE Runtime Environment (build 1.8.0_112-b15)
|
||||
Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)
|
||||
@@ -151,11 +151,11 @@ Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)
|
||||
|
||||
1. 在 [GitHub 仓库](https://github.com/BruceEckel/OnJava8-Examples/archive/master.zip)中下载本书代码示例
|
||||
2. 解压到你所选目录里。
|
||||
3. 使用 Windows 资源管理器, Mac Finder, or Linux 的 Nautilus 或其他等效工具浏览,在该目录下打开 Shell 命令行。
|
||||
3. 使用 Windows 资源管理器, Mac Finder, or Linux 的 Nautilus 或其他等效工具浏览,在该目录下打开 bash 命令行。
|
||||
4. 如果你在正确的目录中,你应该看到该目录中名为 gradlew 和 gradlew.bat 的文件,以及许多其他文件和目录。目录与书中的章节相对应。
|
||||
5. 在命令行中输入下面的命令运行:
|
||||
|
||||
```shell
|
||||
```bash
|
||||
Windows 系统:
|
||||
gradlew run
|
||||
|
||||
@@ -172,7 +172,7 @@ Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)
|
||||
|
||||
本书构建的大量 Gradle 任务都可以自动运行。Gradle 设置使用约定大于配置的方式,简单设置即可具备高可用性。本书中“一起去骑行”的某些任务不适用于此或无法执行成功。以下是你通常会使用上的分级任务列表:
|
||||
|
||||
```java
|
||||
```bash
|
||||
编译本书中的所有 java 文件,除了部分错误示范的
|
||||
gradlew compileJava
|
||||
|
||||
|
||||
@@ -135,14 +135,14 @@ Java 中有两种类型的注释。第一种是传统的 C 风格的注释,以
|
||||
|
||||
但请记住, `/*` 和 `*/` 之间的内容都是被忽略的。所以你将其改为下面的风格也是没有区别的。
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
/* This is a comment that
|
||||
continues across lines */
|
||||
```
|
||||
|
||||
第二种注释形式来自 C++ 。它是单行注释,以 `//` 开头并一直持续到行结束。这种注释方便且常用,因为它很直观和简单。所以你经常看到:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
// 这是单行注释
|
||||
```
|
||||
|
||||
@@ -156,7 +156,7 @@ continues across lines */
|
||||
|
||||
大多数程序语言都有作用域的概念。这将确定在该范围内定义的名称的可见性和生存周期。在 C、C++ 和 Java 中,作用域是由大括号 `{}` 的位置决定的。下面是 Java 代码作用域的一个示例:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
{
|
||||
int x = 12;
|
||||
// 仅 x 变量可用
|
||||
@@ -171,7 +171,7 @@ continues across lines */
|
||||
|
||||
Java 的变量只有在其作用域内才可用。缩进使得 Java 代码更易于阅读。由于 Java 是一种自由形式的语言,额外的空格、制表符和回车并不会影响程序的生成结果。在 Java 中,你不能执行以下操作,即使这在 C 和 C++ 中是合法的:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
{
|
||||
int x = 12;
|
||||
{
|
||||
@@ -187,7 +187,7 @@ Java 的变量只有在其作用域内才可用。缩进使得 Java 代码更易
|
||||
|
||||
Java 对象与基本类型具有不同的生命周期。当我们使用 `new` 关键字来创建 Java 对象时,它的生命周期将会超出作用域的末尾。因此,下面这段代码示例
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
{
|
||||
String s = new String("a string");
|
||||
}
|
||||
@@ -276,11 +276,11 @@ class DataOnly {
|
||||
|
||||
这种默认值的赋予并不适用于局部变量 —— 那些不属于类的属性的变量。 因此,若在方法中定义的基本类型数据,如下:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
int x;
|
||||
```
|
||||
|
||||
这里的变量 x 不会自动初始化为0,因而在使用变量 x 之前,程序员有责任主动地为其赋值(和 C 、C++ 一致)。如果我们忘记了这一步,在 JAVA 中将会提示我们“编译时错误,该变量尚未被初始化”。 这一点做的比 C++ 要更好,在后者中,编译器只是提示警告,而在 JAVA 中则直接报错。
|
||||
这里的变量 x 不会自动初始化为0,因而在使用变量 x 之前,程序员有责任主动地为其赋值(和 C 、C++ 一致)。如果我们忘记了这一步,在 Java 中将会提示我们“编译时错误,该变量尚未被初始化”。 这一点做的比 C++ 要更好,在后者中,编译器只是提示警告,而在 Java 中则直接报错。
|
||||
|
||||
|
||||
<!-- Methods, Arguments,and Return Values -->
|
||||
@@ -288,7 +288,7 @@ class DataOnly {
|
||||
|
||||
在许多语言(如 C 和 C++)中,术语函数(*function*)用于描述命名子程序。在 Java 中,我们使用术语方法(*method*)来表示“做某事的方式”。
|
||||
|
||||
在 JAVA 中,方法决定着对象能接收哪些信息。方法的基础部分包含名称、参数、返回类型、方法体。格式如:
|
||||
在 Java 中,方法决定着对象能接收哪些信息。方法的基础部分包含名称、参数、返回类型、方法体。格式如:
|
||||
|
||||
```java
|
||||
[返回类型][方法名](/*参数列表*/){
|
||||
@@ -385,7 +385,7 @@ Java 采取了一种新的方法避免了以上这些问题:为一个库生成
|
||||
|
||||
无论何时在程序中使用预定义的类,编译器都必须找到该类。在一般情况下,该类已存在于被调用的源代码文件中。此时我们使用该类 —— 即使该类未在文件中稍后定义(Java 消除了所谓的“前向引用”问题)。而那些存在于其他文件中的类怎么样?你可能认为编译器应该足够智能去找到它,但这样是有问题的。想象一下,假如你要使用某个类,但目录中存在多个同名的类(可能用途不同)。或者更糟糕的是,假设你正在编写程序,并且在构建它时,你将向库中添加一个与现有类名称冲突的新类。
|
||||
|
||||
要解决此问题,你必须通过使用 `import` 关键字来告诉 Java 编译器具体要使用的类。import 表示编译器引入一个包,它是一个类库。(在其他语言中,库可以包含函数和数据以及类,但请记住,Java 中的所有活动都在类中进行。)大多数时候,我们都在使用 JAVA 标准库中的组件。有了这些,你不用担心长的反向域名。你只用说,例如:
|
||||
要解决此问题,你必须通过使用 **import** 关键字来告诉 Java 编译器具体要使用的类。**import** 表示编译器引入一个包,它是一个类库。(在其他语言中,库可以包含函数和数据以及类,但请记住,Java 中的所有活动都在类中进行。)大多数时候,我们都在使用 Java 标准库中的组件。有了这些,你不用担心长的反向域名。你只用说,例如:
|
||||
|
||||
```java
|
||||
import java.util.ArrayList;
|
||||
@@ -512,7 +512,7 @@ main() 方法的参数是一个 字符串(**String**) 数组。 参数 `args
|
||||
System.out.println(new Date());
|
||||
```
|
||||
|
||||
上面的示例中,我们创建了一个日期(**Date**)型对象并将其转化为字符串类型并输出到控制台中。 一旦这一行语句执行完毕,我们就不再需要该日期对象了。这时, JAVA 的垃圾回收器就可以将其占用的内存回收,我们无需去主动清除它们。
|
||||
上面的示例中,我们创建了一个日期(**Date**)型对象并将其转化为字符串类型并输出到控制台中。 一旦这一行语句执行完毕,我们就不再需要该日期对象了。这时, Java 的垃圾回收器就可以将其占用的内存回收,我们无需去主动清除它们。
|
||||
|
||||
查看 JDK 文档,我们可以看到, **System** 类下还有很多其他有用的方法。( Java 的牛逼之处还在于,它拥有一个庞大的标准库资源。) 代码示例:
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ Java 是从 C++ 的基础上做了一些改进和简化发展而成的。对于
|
||||
|
||||
运算符的优先级决定了存在多个运算符时一个表达式各部分的计算顺序。Java 对计算顺序作出了特别的规定。其中,最简单的规则就是乘法和除法在加法和减法之前完成。程序员经常都会忘记其他优先级规则,所以应该用括号明确规定计算顺序。代码示例:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
// operators/Precedence.java
|
||||
public class Precedence {
|
||||
|
||||
@@ -62,7 +62,7 @@ public class Precedence {
|
||||
|
||||
如果是为对象赋值,那么结果就不一样了。对一个对象进行操作时,我们实际上操作的是它的引用。所以我们将右边的对象赋予给左边时,赋予的只是该对象的引用。此时,两者指向的堆中的对象还是同一个。代码示例:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
// operators/Assignment.java
|
||||
// Assignment with objects is a bit tricky
|
||||
class Tank {
|
||||
@@ -100,18 +100,18 @@ public class Assignment {
|
||||
|
||||
这种现象通常称为别名(*aliasing*),这是 Java 处理对象的一种基本方式。但是假若你不想这里出现这样的混淆的话,你可以这么做。代码示例:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
t1.level = t2.level;
|
||||
```
|
||||
|
||||
较之前的做法,这样做保留了两个单独的对象,而不是丢弃一个并将 t1 和 t2 绑定到同一个对象。但是这样的操作有点违背 JAVA 的设计原则。对象的赋值是个需要重视的环节,否则你可能收获意外的“惊喜”。
|
||||
较之前的做法,这样做保留了两个单独的对象,而不是丢弃一个并将 t1 和 t2 绑定到同一个对象。但是这样的操作有点违背 Java 的设计原则。对象的赋值是个需要重视的环节,否则你可能收获意外的“惊喜”。
|
||||
|
||||
<!-- Aliasing During Method Calls -->
|
||||
### 方法调用中的别名现象
|
||||
|
||||
当我们把对象传递给方法时,会发生别名现象。
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
// operators/PassObject.java
|
||||
// 正在传递的对象可能不是你之前使用的
|
||||
class Letter {
|
||||
@@ -151,7 +151,7 @@ Java 的基本算术运算符与其他大多编程语言是相同的。其中包
|
||||
Java 也用一种简写形式同时进行运算和赋值操作,由运算符后跟等号表示,并且与语言中的所有运算符一致(只要有意义)。为了将 4 的值赋予给变量 x 同时将结果赋予给 x , 可用 x += 4 来表示。下面带来代码更多代码示例:
|
||||
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
// operators/MathOps.java
|
||||
// The mathematical operators
|
||||
import java.util.*;
|
||||
@@ -238,19 +238,19 @@ u /= v : 9.940527
|
||||
|
||||
一元加 `+` 减 `-` 运算符的操作和二元是相同的。编译器可自动识别使用何种方式解析运算:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
x = -a;
|
||||
```
|
||||
|
||||
上例的代码表意清晰,编译器可正确识别。下面再看一个示例:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
x = a * -b;
|
||||
```
|
||||
|
||||
虽然编译器可以正确的识别,但是程序员可能会迷惑。为了避免混淆,推荐下面的写法:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
x = a * (-b);
|
||||
```
|
||||
|
||||
@@ -265,7 +265,7 @@ x = a * (-b);
|
||||
|
||||
每种类型的运算符,都有两个版本可供选用;通常将其称为“前缀版”和“后缀版”。“前递增”表示 `++` 运算符位于变量或表达式的前面;而“后递增”表示 `++` 运算符位于变量或表达式的后面。类似地,“前递减”意味着 `--` 运算符位于变量或表达式的前面;而“后递减”意味着 `--` 运算符位于变量或表达式的后面。对于前递增和前递减(如 `++a` 或 `--a`),会先执行递增/减运算,再返回值。而对于后递增和后递减(如 `a++` 或 `a--`),会先返回值,再执行递增/减运算。代码示例:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
// operators/AutoInc.java
|
||||
// 演示 ++ 和 -- 运算符
|
||||
public class AutoInc {
|
||||
@@ -310,7 +310,7 @@ C++ 名称来自于递增运算符,同时也代表着“比 C 更进一步”
|
||||
|
||||
关系运算符 `==` 和 `!=` 同样适用于所有对象之间的比较运算,但产生的结果却经常混淆 Java 的初学者。下面是代码示例:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
// operators/Equivalence.java
|
||||
public class Equivalence {
|
||||
public static void main(String[] args) {
|
||||
@@ -331,7 +331,7 @@ false
|
||||
|
||||
上例的结果看起来是我们所期望的。但其实事情并非那么简单。下面我们来创建自己的类:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
// operators/EqualsMethod2.java
|
||||
// 默认的 equals() 方法没有比较内容
|
||||
class Value {
|
||||
@@ -363,7 +363,7 @@ false
|
||||
|
||||
每个逻辑运算符 `&&` (**AND**)、`||`(**OR**)和 `!`(**非**)根据参数的逻辑关系生成布尔值 `true` 或 `false`。下面的代码示例使用了关系运算符和逻辑运算符:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
// operators/Bool.java
|
||||
// 关系运算符和逻辑运算符
|
||||
import java.util.*;
|
||||
@@ -407,7 +407,7 @@ i != j is true
|
||||
(i < 10) || (j < 10) is false
|
||||
```
|
||||
|
||||
在 JAVA 逻辑运算中,我们不能像 C/C++ 那样使用非布尔值, 而仅能使用 **AND**、**OR**、**NOT**。
|
||||
在 Java 逻辑运算中,我们不能像 C/C++ 那样使用非布尔值, 而仅能使用 **AND**、**OR**、**NOT**。
|
||||
下面是一次错误的尝试: ~~a || -~~。 但是,后续表达式使用关系比较生成布尔值,然后对结果使用逻辑运算结果。请注意,如果在预期为 **String** 类型的位置使用 **boolean**类型的值,则结果会自动转为适当的文本格式。
|
||||
|
||||
我们可以将前一个程序中 **int** 的定义替换为除 **boolean** 之外的任何其他基本数据类型。
|
||||
@@ -419,7 +419,7 @@ i != j is true
|
||||
|
||||
逻辑运算符支持一种称为“短路”(*short-circuiting*)的现象。整个表达式会在运算到可以明确结果时就停止并返回结果,这意味着该逻辑表达式的后半部分不会被执行到。代码示例:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
// operators / ShortCircuit.java
|
||||
// 逻辑运算符的短路行为
|
||||
public class ShortCircuit {
|
||||
@@ -461,7 +461,7 @@ expression is false
|
||||
|
||||
每个测试都对参数执行比较并返回 `true` 或 `false`。同时控制台也会在方法执行时打印他们的执行状态。 下面的表达式:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
test1(0)&& test2(2)&& test3(2)
|
||||
```
|
||||
|
||||
@@ -476,7 +476,7 @@ test1(0)&& test2(2)&& test3(2)
|
||||
|
||||
通常,当我们向程序中插入一个字面值常量(**Literal**)时,编译器会确切地识别它的类型。当类型不明确时,必须辅以字面值常量关联来帮助编译器识别。代码示例:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
// operators/Literals.java
|
||||
public class Literals {
|
||||
public static void main(String[] args) {
|
||||
@@ -558,7 +558,7 @@ Java 7 引入了二进制的字面值常量,由前导 `0B` 或 `0B` 表示,
|
||||
Java 7 中有一个深思熟虑的补充:我们可以在数字文字中包含下划线 `_`,以使结果更清晰。这对于大数值的分组数字特别有用。代码示例:
|
||||
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
// operators/Underscores.java
|
||||
public class Underscores {
|
||||
public static void main(String[] args) {
|
||||
@@ -599,7 +599,7 @@ public class Underscores {
|
||||
|
||||
指数总是采用一种我认为很不直观的记号方法:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
// operators/Exponents.java
|
||||
// "e" 表示 10 的几次幂
|
||||
public class Exponents {
|
||||
@@ -628,7 +628,7 @@ public class Exponents {
|
||||
|
||||
注意如果编译器能够正确地识别类型,就不必使用尾随字面值常量。对于下述语句:
|
||||
|
||||
```JAVA
|
||||
```java
|
||||
long n3 = 200;
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user