ITPub博客

首页 > 应用开发 > Javascript > Java JDK 9学习笔记

Java JDK 9学习笔记

原创 Javascript 作者:qinghuawenkang 时间:2018-10-23 10:04:15 0 删除 编辑

北 京
内 容 简 介
本书是作者多年来教学实践经验的总结,汇集了学员在学习 Java 或认证考试时遇到的概念、操
作、应用等问题及解决方案。
本书针对
Java SE 9 新功能全面改版,无论是章节架构或范例程序代码,都做了重新编写与全面
翻新,并详细介绍了
Java 9 的模块化, JVM JRE Java SE API JDK IDE 之间的对照关系。必
要时可从
Java SE API 的源代码分析,了解各种语法在 Java SE API 中如何应用。对于建议练习的范
例提供了
Lab 文档,以突出练习重点。此外,本书还将 IDE 操作纳为教学内容之一,让读者能与实
践相结合,轻松快速掌握
Java 编程技巧。
本书适合
Java 的初、中级读者以及广大 Java 应用开发人员阅读。
本书资料可通过
http://www.tupwk.com.cn/downpage 免费下载。
北京市版权局著作权合同登记号 图字: 01-2018-3785
本书封面贴有清华大学出版社防伪标签,无标签者不得销售。
版权所有,侵权必究。侵权举报电话: 010-62782989 13701121933
图书在版编目(CIP)数据
Java JDK 9
学习笔记 / 林信良编著 . —北京:清华大学出版社, 2018
ISBN 978-7-302-50118-3
. J … Ⅱ . ①林… Ⅲ . JAVA 语言-程序设计 Ⅳ . TP312.8
中国版本图书馆 CIP 数据核字 (2018) 100148
责任编辑: 王 定
封面设计: 牛艳敏
版式设计: 思创景点
责任校对: 孔祥峰
责任印制: 李红英
出版发行 :清华大学出版社
网 址 http://www.tup.com.cn, http://www.wqbook.com
地 址
:北京清华大学学研大厦 A 邮 编 100084
社 总 机
010-62770175 邮 购 010-62786544
投稿与读者服务
010-62776969 c-service@tup.tsinghua.edu.cn
质 量 反 馈
010-62772015 zhiliang@tup.tsinghua.edu.cn
印 装 者
:清华大学印刷厂
经 销 :全国新华书店
开 本 185mm × 260mm 印 张 36.75 字 数 941 千字
版 次 2018 6 月第 1 印 次 2018 6 月第 1 次印刷
定 价 98.00
—————————————————————————————————————————————
产品编号:
079536-01

当你拿起这本书,翻开这篇序,我便有了机会问你一个问题:“为什么想翻开这本书?”
“这个梗上一版的序用过啦!”
好吧!那学 Java 目的是什么呢?从事程序设计?那么我就有个新梗了:“什么是‘设计’ 呢?”
唔!好难回答的问题,来拜一下 Google 大神吧!搜索“什么是设计”,看完答案之后就更不
懂了,在没有一个具体目标之前,得到的可能都是近乎空洞的答案吧!
试着在身边找个东西,比如键盘,你觉得设计得好吗?不好?哪里觉得不好?触感!什么样
的是不好?反馈的力道!反馈是来自哪里?键轴!键轴是由哪些成分组成的呢?底座、弹簧、轴
心、轴帽!造成反馈差异性的主要来源是什么?弹簧和轴心!喔?弹簧啊?它的圈数是多少
呢?……
当你逐一挖掘出其中的元素之后,面对一个觉得设计不错的键盘,或许你就能知道其中有哪
些“设计”了。
很多时候,当谈到一件东西设计得好或不好时,并不会明确地知道自己在讲什么,只是综合
了各种感觉而得到的模糊结论。当然,在平时生活中,并不用每件事物都得探究到底,只是当某
个事物是喜爱的、想赖以维生的,或者是两者综合,以为喜欢某个事物,因而想要进一步赖以维
生,这个时候就不能只靠个模糊结论来搪塞下去了。
当你拿起这本书,表示选择了 Java 这门程序设计语言,为什么呢?因为 Java 可以写程序。可
以写程序的语言很多啊!因为可以写手机 APP?那为什么不选 Objective-C 或 Swift 呢?因为听说
业界很缺?喔!缺的是哪个工作性质的职位?手机……好吧!再问下去,可能有人只是被说服参
加了三个月的 APP 补习课程,只好硬着头皮继续学下去了……
Java 本身是门程序设计语言,本身就有设计的成分在里头,基于面向对象典范,后来有了一
些函数式典范的影子。 Java 不是门简洁的语言,然而为了解决这方面问题,近来在语言设计上有
了不少简化语法,把 Java 用在许多层面, Java 面对了为模块化制订标准的需求……
然而解决问题并不能只靠程序语言,面对不同的问题,需要设计各种流程,也有不同的数据
结构设计。对于更复杂的问题,得靠更有效率的算法。当项目有一定规模,有弹性的架构设计是
必要的。为了掌握程序的行为,就得设计可测试的程序;想要避免被入侵,必须将安全上的设计
纳入考虑;当庞大的数据迎面而来,平行化方案的设计可能就得出现了……
设计是用来解决问题的!你喜欢或讨厌一种设计,代表它在解决问题上是否顺你的心、得你
的意,从而认定一个设计是否优雅。

II
既然已经选择了 Java, 那表示你得接受它的设计了。 那么接下来的问题, 就在于怎么使用 Java
来表达你的设计了。不过,这也得真的有能够表达的设计,你有能表达的算法设计吗?数据结构
设计?测试上的设计?架构上的设计?安全上的设计?平行处理的设计?……
过去、现在或未来,你写的程序中,真的有“设计”的成分在吗?
林信良
2017 年 12 月
导 读
这份导读让你可以更了解如何使用本书。
新旧版差异
就目录上来说,你可以看出的差异是,上一版为 18个章节,新版为 19 个章节,第 19 章“深
入模块化”是新的章节,也是 JDK9 最重要的新增功能。然而,认识模块化最好的方式是从实际
的例子着手,因此第 1~18章,全部的范例都是采用模块项目构建。而在各章说明时若有需要,也
适时地带入了常用的模块化概念。第 19 章一开始则是整理前 18 个章节遇到过的模块化介绍,然
后紧接着深入探讨模块化。
当然,照例要谈一些 JDK9 的其他新增功能,散落在各章节中适当的地方介绍。如果发现页
侧有 图标,表示提及 JDK9 新功能,本书还提供了 JDK9 新功能快速查询目录。
虽然程序常用来处理计算,然而许多开发者对数字处理其实认识不多,因而第 15章通用 API
增加了数字处理的内容;为了认识 JDK9 Stack-Walking API,读者有必要先认识如何取得并运用
StackTraceElement来进行堆栈追踪,因而在第 15章还增加了一个小节来介绍堆栈追踪,对于读者
了解应用程序行为,或者是处理 Bug,应该会有所帮助。
在第 2 章介绍了模块化之后,范例项目便基于模块化设计了,并使用了 JDK9 的语法增强或
改进部分程序代码;在 9.1.6节介绍 Lambda 之后,为了提高可读性,使用 Lambda相关语法或 API
来操作程序范例。
旧版有个附录 B“窗口程序设计”,在新版中删掉了,这表示了 Java 在窗口程序这块的地位。
当然, Java有 Java FX这项技术,如果仍希望使用 Java进行窗口程序设计,可以寻找 Java FX的专
书。附录 B 虽然不在了,不过范例项目的程序代码留着作为第 19 章的练习,读者可以自行研读
原始码,并试着将之模块化。如果一定需要点说明,可以参考旧版《Java SE 6 技术手册》第 19
章说明:
„ github.com/JustinSDK/JavaSE6Tutorial/blob/master/docs/CH19.md
字型
本书正文中与程序代码相关的文字,都用固定字体来加以呈现,以与一般名词相区别。例如,
JDK是一般名词,而
String 则是程序代码相关文字,所以使用了固定字体以区分。
IV
程序范例
读者可以在以下网址下载本书的范例:
„ http://www.tupwk.com.cn/downpage
„ http://books.gotop.com.tw/v_ACL052100
本书许多范例都使用完整程序操作来展现,如看到以下程序代码示范时:
ClassObject Guess.java
package cc.openhome;
import java.util.Scanner;
import static java.lang.System.out;
public class Guess {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int number = (int) (Math.random() * 10);
int guess;
do {
System.out.print("猜数字(0 ~ 9) :");
guess = scanner.nextInt();
} while(guess != number);
out.println("猜中了...XD");
}
}
范例开始的左边名称为 ClassObject 表示可以在范例文件的 samples 文件夹的各章节文件夹中
找到对应的 ClassObject项目;而右边名称为 Guess.java表示可以在项目中找到 Guess.java文件。如
果程序代码中出现标号与提示文字,表示在后续的正文中,会有对应于标号及提示的更详细说明。
原则上,建议读者每个项目范例都能亲手动作撰写,但出于教学时间或操作时间上的考虑,
本书有建议进行的练习。如果在范例开始前有个 图标,例如:
Game1 SwordsMan.java
package cc.openhome;
public class SwordsMan
extends Role {
public void fight() {
System.out.println("挥剑攻击");
}
}
表示建议范例动手操作,而且在范例文件的 labs 文件夹中提供了练习项目的基础,打开项目
后,完成项目中遗漏或必须补齐的程序代码或设定即可。
如果使用以下程序代码呈现,则表示它是一个完整的程序内容,而不是项目的一部分,这主
要用来展现一个完整文档的撰写方法。
Y 建立 Scanner 实例
Z 取得下一个整数
X 告诉编译程序接下来想偷懒
导 读
V
public class Hello {
public static void main(String[] args) {
System.out.println("Hello!World!");
}
}
如果使用以下程序代码,则表示它是个代码段,主要展现程序撰写时需要特别注意的片段:
SwordsMan swordsMan = new SwordsMan();
...
System.out.printf(" 剑士 (%s, %d, %d)%n", swordsMan.getName(),
swordsMan.getLevel(), swordsMan.getBlood());
Magician magician = new Magician();
...
System.out.printf(" 魔法师 (%s, %d, %d)%n", magician.getName(),
magician.getLevel(), magician.getBlood());
提示框
在本书中会出现以下提示框:
针对课程中所提到的观点,提供了一些额外的资源或思考方向,暂时忽略这些提示对
课程的影响,但有时间的话,针对这些提示做阅读、思考或讨论是有帮助的。
针对课程中所提到的观点,以提示框方式特别呈现出必须注意的一些使用方式、陷阱
或避开问题的方法,看到这个提示框时请读者集中精神阅读。
附录
范例文件包括本书中的所有范例,提供 NetBeans范例项目,附录 A用于说明如何使用这些范
例项目。
联系作者
若有本书勘误反馈等相关书籍问题,可通过网站与作者联系。网址如下:
http://openhome.cc


目 录
Chapter 1 Java 平台概论 ·················· 1
1.1 Java 不只是语言························2
1.1.1 前世今生 ································ 2
1.1.2 三大平台 ································ 5
1.1.3 JCP JSR····························· 6
1.1.4 Oracle JDK OpenJDK ······· 7
1.1.5 建议的学习路径 ···················· 8
1.2 JVM/JRE/JDK ·························12
1.2.1 什么是 JVM························· 12
1.2.2 区分 JRE JDK ················· 14
1.2.3 下载、安装 JDK·················· 15
1.2.4 认识 JDK 安装内容 ············· 18
1.3 重点复习 ·································19
Chapter 2 从 JDK 到 IDE················· 21
2.1 从 Hello World 开始················22
2.1.1 撰写 Java 原始码 ················· 22
2.1.2 PATH 是什么 ························ 24
2.1.3 JVM( java ) CLASSPATH ···· 27
2.1.4 编译程序 ( javac )
CLASSPATH ·························· 29
2.2 管理原始码与位码文档 ··········30
2.2.1 编译程序 ( javac )
SOURCEPATH ························ 30
2.2.2 使用 package 管理类 ·········· 32
2.2.3 使用 import 偷懒 ··············· 34
2.3 初识模块平台系统··················36
2.3.1 JVM( java ) modulepath ··································· 37
2.3.2 编译程序 ( javac )
module-path ······················ 39
2.3.3 编译程序 ( javac )
module-source-path ······· 40
2.4 使用 IDE··································41
2.4.1 IDE 项目管理基础 ·············· 41
2.4.2 使用了哪个 JRE ·················· 47
2.4.3 类文档版本 ························· 49
2.5 重点复习 ·································51
Chapter 3 基础语法 ·························53
3.1 类型、变量与运算符··············54
3.1.1 类型 ····································· 54
3.1.2 变量 ····································· 57
3.1.3 运算符 ································· 60
3.1.4 类型转换 ····························· 65
3.2 流程控制 ·································68
3.2.1 if...else 条件式 ·············· 68
3.2.2 switch 条件式 ···················· 70
3.2.3 for 循环 ······························ 72
3.2.4 while 循环 ·························· 73
3.2.5 break continue ·············· 74
3.3 重点复习 ·································76
3.4 课后练习 ·································77
Chapter 4 认识对象 ·························78
4.1 类与对象 ·································79
4.1.1 定义类 ································· 79
4.1.2 使用标准类 ························· 81
4.1.3 对象指定与相等性 ·············· 84
4.2 基本类型打包器······················86
4.2.1 打包基本类型 ······················ 86
4.2.2 自动装箱、拆箱 ·················· 87
4.2.3 自动装箱、拆箱的内幕 ······ 88
4.3 数组对象 ·································90

VIII
4.3.1 数组基础 ······························ 91
4.3.2 操作数组对象 ······················ 93
4.3.3 数组复制 ······························ 98
4.4 字符串对象····························100
4.4.1 字符串基础 ······················· 101
4.4.2 字符串特性 ······················· 103
4.4.3 字符串编码 ······················· 107
4.5 查询 Java API 文件 ···············108
4.6 重点复习 ·······························113
4.7 课后练习 ·······························114
Chapter 5 对象封装······················· 116
5.1 何谓封装 ·······························117
5.1.1 封装对象初始流程 ··········· 117
5.1.2 封装对象操作流程 ··········· 119
5.1.3 封装对象内部数据 ··········· 121
5.2 类语法细节····························123
5.2.1 public 权限修饰 ············· 123
5.2.2 关于构造函数 ··················· 125
5.2.3 构造函数与方法重载 ······· 126
5.2.4 使用 this ························· 128
5.2.5 static 类成员 ················· 130
5.2.6 不定长度自变量 ··············· 135
5.2.7 内部类 ······························ 136
5.2.8 传值调用 ··························· 138
5.3 重点复习 ·······························140
5.4 课后练习 ·······························141
Chapter 6 继承与多态 ··················· 142
6.1 何谓继承 ·······························143
6.1.1 继承共同行为 ··················· 143
6.1.2 多态与 is-a························ 147
6.1.3 重新定义行为 ··················· 150
6.1.4 抽象方法、抽象类 ··········· 153
6.2 继承语法细节························154
6.2.1 protected 成员 ··············· 154
6.2.2 重新定义的细节 ··············· 156
6.2.3 再看构造函数 ··················· 157
6.2.4 再看 final 关键字 ··········· 159
6.2.5 java.lang.Object ·········· 160
6.2.6 关于垃圾收集 ···················· 165
6.2.7 再看抽象类 ······················· 167
6.3 重点复习 ·······························169
6.4 课后练习 ·······························170
Chapter 7 接口与多态····················171
7.1 何谓接口 ·······························172
7.1.1 接口定义行为 ···················· 172
7.1.2 行为的多态 ······················· 175
7.1.3 解决需求变化 ···················· 178
7.2 接口语法细节························183
7.2.1 接口的默认 ······················· 183
7.2.2 匿名内部类 ······················· 187
7.2.3 使用 enum 枚举常数 ········· 190
7.3 重点复习 ·······························192
7.4 课后练习 ·······························193
Chapter 8 异常处理 ·······················194
8.1 语法与继承架构····················195
8.1.1 使用 try catch ·············· 195
8.1.2 异常继承架构 ···················· 197
8.1.3 要抓还是要抛 ···················· 202
8.1.4 贴心还是造成麻烦 ············ 205
8.1.5 认识堆栈追踪 ···················· 206
8.1.6 关于 assert ······················ 210
8.2 异常与资源管理····················213
8.2.1 使用 finally ···················· 213
8.2.2 自动尝试关闭资源 ············ 215
8.2.3 java.lang.AutoCloseable
接口 ··································· 217
8.3 重点复习 ·······························221
8.4 课后练习 ·······························222
Chapter 9 Collection 与 Map ····223
9.1 使用
Collection 收集对象 ····224
9.1.1 认识 Collection 架构 ····· 224
9.1.2 具有索引的 List ·············· 225
9.1.3 内容不重复的 Set ············ 228
IX
目 录
9.1.4
支持队列操作的 Queue ···· 232
9.1.5 使用泛型 ··························· 234
9.1.6 简介 Lambda 表达式 ········ 238
9.1.7 Interable
Iterator ························· 240
9.1.8 Comparable
Comparator ····················· 243
9.2 键值对应的
Map ·····················248
9.2.1 常用 Map 操作类 ··············· 249
9.2.2 访问 Map 键值 ··················· 252
9.3 不可变的
Collection
Map ·········································· 255
9.3.1 浅谈不可变特性 ··············· 255
9.3.2 Collection s
unmodifiableXXX()
方法 ·································· 256
9.3.3 List Set Map of()
方法 ·································· 258
9.4 重点复习 ·······························260
9.5 课后练习 ·······························262
Chapter 10 输入/输出···················· 263
10.1
InputStream
OutputStream ··························264
10.1.1 串流设计的概念 ············· 264
10.1.2 串流继承架构 ················· 266
10.1.3 串流处理装饰器 ············· 269
10.2 字符处理类····························273
10.2.1 Reader Writer 继承
架构
································ 274
10.2.2 字符处理装饰器 ············· 275
10.3 重点复习································277
10.4 课后练习································278
Chapter 11 线程与并行 API··········· 279
11.1 线程········································280
11.1.1 线程简介 ························· 280
11.1.2 Thread Runnable ······ 282
11.1.3 线程生命周期 ················· 284
11.1.4 关于 ThreadGroup ·········· 290
11.1.5 synchronized
volatile ························ 292
11.1.6 等待与通知 ······················ 301
11.2 并行 API ································305
11.2.1 Lock ReadWriteLock
Condition ······················ 305
11.2.2 使用 Executor ················ 313
11.2.3 并行 Collection 简介 ··· 323
11.3 重点复习································326
11.4 课后练习································327
Chapter 12 Lambda·······················328
12.1 认识 Lambda 语法 ·················329
12.1.1 Lambda 语法概览 ············ 329
12.1.2 Lambda 表达式与函数
接口
································· 332
12.1.3 Lambda 上 this
final ······························· 334
12.1.4 方法与构造函数参考 ······ 336
12.1.5 接口默认方法 ·················· 338
12.2 Functional 与 Stream API·······343
12.2.1 使用 Optional 取代
null ································· 343
12.2.2 标准 API 的函数接口 ······ 345
12.2.3 使用 Stream 进行管道
操作
································· 348
12.2.4 进行 Stream reduce
collect ······················ 351
12.2.5 关于 flatMap() 方法 ······ 356
12.2.6 Stream 相关 API ············· 359
12.2.7 JDK9 Optional
Stream 增强 ···················· 360
12.3 Lambda、平行化与异步
处理········································362
12.3.1 Stream 与平行化 ············ 362
12.3.2 Arrays 与平行化 ············ 366
X
12.3.3 CompletableFuture
非同步处理 ····················· 367
12.3.4 JDK9 CompletableFuture
增强 ································ 369
12.4 重点复习································370
12.5 课后练习································371
Chapter 13 时间与日期 ················· 372
13.1 认识时间与日期 ····················373
13.1.1 时间的度量 ····················· 373
13.1.2 年历简介 ························· 374
13.1.3 认识时区 ························· 375
13.2 认识
Date Calendar ············376
13.2.1 时间轴上瞬间的 Date ···· 376
13.2.2 格式化时间日期的
DateFormat ···················· 377
13.2.3 处理时间日期的
Calendar ························ 379
13.2.4 设定 TimeZone ··············· 382
13.3 新时间日期 API·····················383
13.3.1 机器时间观点的 API ······ 383
13.3.2 人类时间观点的 API ······ 385
13.3.3 对时间的运算 ················· 387
13.3.4 年历系统设计 ················· 389
13.4 重点复习································390
13.5 课后练习································391
Chapter 14 NIO 与 NIO2··············· 393
14.1 认识 NIO································394
14.1.1 NIO 概述 ························· 394
14.1.2 Channel 架构与操作 ······ 395
14.1.3 Buffer 架构与操作 ········ 396
14.2 NIO2 文件系统······················398
14.2.1 NIO2 架构 ······················· 398
14.2.2 操作路径 ························· 399
14.2.3 属性读取与设定 ············· 401
14.2.4 操作文档与目录 ············· 404
14.2.5 读取、访问目录 ············· 406
14.2.6 过滤、搜索文档 ············· 410
14.3 重点复习································412
14.4 课后练习································413
Chapter 15 通用 API······················414
15.1 日志········································415
15.1.1 日志 API 简介 ·················· 415
15.1.2 指定日志层级 ·················· 417
15.1.3 使用 Handle r
Formatter ······················ 419
15.1.4 自定义 Handler Formatter
Filter ························ 420
15.1.5 使用 logging.
properties
···················· 422
15.2 国际化基础····························423
15.2.1 使用 ResourceBundle ···· 423
15.2.2 使用 Locale ···················· 424
15.3 规则表示式····························426
15.3.1 规则表示式简介 ·············· 426
15.3.2 Pattern Matcher ······· 433
15.4 处理数字································435
15.4.1 使用 BigInteger ············ 435
15.4.2 使用 BigDecimal ············ 437
15.4.3 数字的格式化 ·················· 439
15.5 再谈堆栈追踪························441
15.5.1 获取
StackTraceElement ······· 441
15.5.2 JDK9 StackWalking API ···················· 443
15.6 重点复习································447
15.7 课后练习································448
Chapter 16 整合数据库··················449
16.1 JDBC 入门 ·····························450
16.1.1 JDBC 简介 ······················· 450
16.1.2 连接数据库 ······················ 454
16.1.3 使用 Statement
ResultSet ······················ 459
16.1.4 使用 PreparedStatement
CallableStatement ······ 464
XI
目 录
16.2 JDBC 进阶 ·····························468
16.2.1 使用 DataSource 取得
联机
································ 468
16.2.2 使用 ResultSet 卷动、
更新数据
························· 471
16.2.3 批次更新 ························· 473
16.2.4 Blob Clob ·················· 474
16.2.5 交易简介 ························· 474
16.2.6 metadata 简介 ··············· 481
16.2.7 RowSet 简介 ···················· 484
16.3 重点复习································486
16.4 课后练习································487
Chapter 17 反射与类加载器·········· 489
17.1 运用反射································490
17.1.1 Class .class 文档 ········ 490
17.1.2 使用 Class.
forName()
······················ 492
17.1.3 Class 获得信息 ········· 494
17.1.4 Class 建立对象 ········· 496
17.1.5 操作对象方法与成员 ······ 499
17.1.6 动态代理 ························· 501
17.1.7 当反射遇上模块 ············· 505
17.1.8 使用 ServiceLoader ····· 511
17.2 了解类加载器 ························513
17.2.1 JDK9 类加载器层级 ······· 513
17.2.2 建立 ClassLoader
实例 ································· 516
17.3 重点复习································517
17.4 课后练习································519
Chapter 18 自定义泛型、枚举与
注释 ···························· 520
18.1 自定义泛型····························521
18.1.1 使用 extends ? ··········· 521
18.1.2 使用 super ? ··············· 525
18.2 自定义枚举····························528
18.2.1 了解 java.lang.
Enum
·························· 528
18.2.2 enum 高级运用 ················· 531
18.3 关于注释································536
18.3.1 常用标准注释 ·················· 536
18.3.2 自定义注释类型 ·············· 540
18.3.3 执行时期读取注释信息 ·· 545
18.4 重点复习································548
18.5 课后练习································549
Chapter 19 深入模块化··················550
19.1 运用模块································551
19.1.1 模块的种类 ······················ 551
19.1.2 requires exports
opens 细节 ······················ 554
19.1.3 修补模块 ·························· 557
19.1.4 放宽模块封装与依赖 ······ 558
19.2 模块 API ································560
19.2.1 使用 Module ···················· 560
19.2.2 使用
ModuleDescriptor ········ 562
19.2.3 浅谈 ModuleLayer ·········· 562
19.3 打包模块································564
19.3.1 使用 jar 打包 ·················· 564
19.3.2 使用 jmod 打包 ················ 566
19.3.3 使用 jlink 建立执行时期
映像
································· 568
19.4 重点复习································569
19.5 课后练习································570
Appendix··········································571
A.1 项目环境配置 ·························572
A.2 打开案例·································572


Java SE 9 新功能索引
Java SE 9后的特性版本时间轴变动································································································ 15
JDK 9 文档实体布局变动·················································································································· 18
初探模块平台系统 ····························································································································· 36
javac 新增 -release 参数··················································································································· 50
支持 Unicode 8.0·································································································································· 54
内建 jshell············································································································································· 56
Java API文件支持搜索功能············································································································ 112
StackTraceElement 新增方法·········································································································· 207
Try-with-resources 语法改进 ············································································································ 217
定义匿名类别时的泛型语法改进 ·································································································· 239
List Set Map 新增 of( ) 方法 ···································································································· 258
接口支持定义
private 方法 ··········································································································· 340
Collectors 新增 filtering( ) 方法 ······························································································· 356
Collectors 新增 flatMapping( ) 方法 ··························································································· 359
Optional Stream 增强·················································································································· 360
CompletableFuture 增强 ·················································································································· 369
支持 UTF-8编码的.properities 文件································································································ 425
Stack-Walking API ····························································································································· 443
反射与类加载器机制······················································································································· 490
@Deprecated 增强······························································································································ 537
ElementType 新增 MODULE ················································································································· 545
深入模块化········································································································································ 551


学习目标
„ Java 版本迁移简介
„ 认识 Java SE、 Java EE、 Java ME
„ 认识 JDK 规范与操作
„ 了解 JVM、 JRE 与 JDK
„ 下载与安装 JDK
Java 平台概论 1
1.1 Java 不只是语言
从 1995 年至今, Java 已经过了 20 多个年头,经过这些年的改进,正如本节标题所示, Java
已不仅是个程序语言,也代表了解决问题的平台(Platform),更代表了原厂、各个厂商、社群、
开发者与用户沟通的成果。若仅以程序语言的角度来看待 Java,正如冰山一角,你仅看到 Java
身为程序语言的一部分,而没看到 Java 身为程序语言之外,更可贵也更为庞大的资源。
1.1.1 前世今生
一个语言的诞生有其目的,因为这个目的而成就了该语言的主要特性。探索 Java 的历史演
变,对于掌握 Java 特性与各种可用资源,有很大帮助。
1. Java 诞生
Java 最早是 Sun 公司绿色项目(Green Project)中撰写 Star7 应用程序的程序语言,当时的名
称并不是 Java,而是 Oak。
绿色项目始于 1990 年 12 月,由 Patrick Naughton、 Mike Sheridan 与 James Gosling(James
Gosling 被尊称为 Java 之父)主持,目的是希望构筑出下一波计算机应用趋势并加以掌握,他们
认为下一波计算机应用趋势会集中在消费性数字产品(就像现在的 PDA、手机等消费性电子商
品)的使用上。 1992 年 9 月 3 日, Green Team 项目小组展示了 Star7 手持设备,这个设备具备无
线网络连接、 5 寸 LCD 彩色屏幕、 PCMCIA 接口等功能,而 Oak 在绿色项目中的目的,是用来
撰写 Star7 上应用程序的程序语言。
Oak 名称的由来,是因为 James Gosling 的办公室窗外有一棵橡树(Oak),就取了这个名称。
但后来发现 Oak 已经被注册了,工程师们边喝咖啡边讨论着新名称,最后灵机一动而改名为
Java。
Java 本身有许多为了节省资源而作的设计,如动态加载类别文档、字符串池(String Pool)
等特性,这是因为 Java 一开始就是为了消费性数字产品而设计,而这类小型装置通常有着有限
内存与运算资源。
全球信息网(World Wide Web)兴起, Java Applet 成为网页互动技术的代表。
1993 年第一个全球信息网浏览器 Mosaic 诞生, James Gosling 认为互联网与 Java 的一些特
性不谋而合,利用 Java Applet 在浏览器上展现互动性媒体,在当时而言,对视觉感官是一种
革命性的颠覆。 Green Team 仿照 Mosaic 开发出以 Java 技术为基础的浏览器 WebRunner(原名
为 BladeRunner),后来改名为 HotJava。虽然 HotJava只是一个展示性产品,但它使用 Java Applet
展现的多媒体效果立即吸引了许多人的注意,图 1.1 所示即为 JDK 所附的 Java Applet 范例。
1995 年 5 月 23 日(这一天被公认为 Java 的诞生日),正式将 Oak 改名为 Java, Java
Development Kits(当时 JDK 的全名)1.0a2 版本正式对外发表。 到 1996 年, Netscape Navigator 2.0
也正式支持 Java, Microsoft Internet Explorer 也开始支持 Java。从此, Java 在互联网的世界中逐
渐风行起来。虽然 Star7 产品并不被当时消费性市场接受,绿色项目面临被裁撤的命运,然而
全球信息网的兴起却给了 Java 新的生命与舞台。


2. 版本演进
随着 Java 越来越受到瞩目, Sun 在 1998 年 12 月 4 日发布 Java 2 Platform,简称 J2SE 1.2。
Java 开发者版本一开始是以 Java Development Kit 名称发表,简称 JDK,而 J2SE 则是平台名
称,包含了 JDK 与 Java 程序语言。
Java 平台标准版约以两年为周期推出重大版本更新, 1998 年 12 月 4 日发表 J2SE 1.2,
2000 年 5 月 8 日发表 J2SE 1.3, 2002 年 2 月 13 日发表 J2SE 1.4, Java 2 这个名称也从 J2SE 1.2
开始沿用至各个版本。
2004 年 9 月 29 日发表的 Java 平台标准版的版号不是 1.5,而直接跳到 5.0,称为 J2SE 5.0,
这是为了彰显这个版本与之前版本有极大不同,如语法上的简化、增加泛型(Generics)、枚举
(Enum)、注释(Annotation)等重大功能。
2006 年 12 月 11 日发表的 Java 平台标准版,除了版本号之外,名称也有了变化,称为 Java
Platform, Standard Edition 6,简称 Java SE 6。 JDK6 全名则称为 Java SE Development Kit
6,也就是不再像以前 Java 2 带有 2 这个号码,版本号 6 或 1.6.0 都使用, 6 是产品版本(Product
Version),而 1.6.0 是开发者版本(Developer Version)。
大部分的 Java 标准版平台都会取个代码名称(Code Name),例如 J2SE 5.0 的代码名称为
Tiger(老虎),为了引人注目,在发表会上还真的抱了一只小白老虎出来作为噱头,而许多书的
封面也相应地放上老虎的图片。有关 JDK 代码名称与发布日期,如表 1.1 所示。
表 1.1 Java 版本、代码名称与发布日期

版 本 代 码 名 称 发 布 日 期
JDK 1.1.4 Sparkler(烟火) 1997/9/12
JDK 1.1.5 Pumpkin(南瓜) 1997/12/3
JDK 1.1.6 Abigail(圣经故事人物名称) 1998/4/24
JDK 1.1.7 Brutus(罗马政治家名称) 1998/9/28
JDK 1.1.8 Chelsea(足球俱乐部名称) 1999/4/8
J2SE 1.2 Playground( 游乐场 ) 1998/12/4
J2SE 1.2.1 1999/3/30
J2SE 1.2.2 Cricket(蟋蟀) 1999/7/8
J2SE 1.3 Kestrel( 红隼 ) 2000/5/8


( 续表 )

版 本 代 码 名 称 发 布 日 期
J2SE 1.3.1 Ladybird(瓢虫) 2001/5/17
J2SE 1.4.0 Merlin( 魔法师名称 ) 2002/2/13
J2SE 1.4.1 Hopper(蚱蜢) 2002/9/16
J2SE 1.4.2 Mantis(螳螂) 2003/6/26
J2SE 5.0 Tiger( 老虎 ) 2004/9/29
Java SE 6 Mustang( 野马 ) 2006/12/11
Java SE 7 Dolphin( 海豚 ) 2011/7/28
Java SE 8 2014/3/18
Java SE 9 2017/9/21


撰写本书时,表 1.1 参考的数据源网址如下 ( 其中列出至 J2SE 5.0)
http://www.oracle.com/technetwork/java/javase/codenames-136090.html
3. 江山易主
之前谈过, Java 约以两年为周期推出重大版本更新,正如表 1.1 所示, J2SE 1.2、 J2SE 1.3、
J2SE 1.4.0、 J2SE 5.0、 Java SE 6 推出的时间间隔,差不多都是两年。然而从 Java SE 6 之后,
Java 开发人员足足等了四年多,才等到新版本的推出,不禁让人想问: Java 怎么了?
原因有许多, Java SE 7 对新版本的规划摇摆不定,涵盖许多不易实现的新特性,加上 Sun
一直营收低迷不振,影响了新版本的推动。新版本推出日期承诺不断推迟,从 2009 年推迟至
2010 年初,又突然宣布将加入原本不愿划入 Java SE 7 的 Closure 语法,并将推出日期推迟至
2010 年底。 2010 年年中传出 IBM 与 Sun 密谈并购失败,没隔几日,即爆出 Oracle 宣布并购
Sun, Java 也正式成为 Oracle 所属。
并购会带来一连串的组织重整,导致 Java SE 7 推出日期再度推迟,为了对停滞不前的 Java
注入活水,决定先将现有已实现或较易实现的特性放入 Java SE 7 中,将未定方案或较难实现的
特性放入 Java SE 8 中(比如 Lambda), 2010 年底 JCP(Java Community Process,稍后即会说明这
个组织是什么)终于通过了 Java SE 7 与 Java SE 8 的规划地图(Roadmap),并预定于 2011 年 7 月
左右推出 Java SE 7,这次总算没有推迟, Java SE 7 正式于 2011 年 7 月 28 日发布。
Java SE 8 实际上也是一波三折,原定应于 2013 年发布,却因为接二连三爆出的 Java 安全
漏洞,迫使 Java 开发团队决定先行检查修补 Java 安全问题,几经延后,最后确定发布 Java SE 8
的时间为 2014 年 3 月 18 日。
实际上,当初为了及早推出 Java SE 7,被推迟至 Java SE 8 的重大特性还有 Jigsaw,也就
是 Java 模块平台系统(Java Platform Module System)。然而当时为了修补 Java 安全问题已经使得
Java SE 8 多次延迟,为了能如期推出 Java SE 8, Java 模块平台系统并没有在 Java SE 8 中实现,
而被放到了 Java SE 9 中并成为重大特性之一。虽然如此,推出过程中又因为开发不及,以及发
生了 JCP 执行委员会(JCP Executive Committee)曾经投票否决了 Java 模块平台系统等因素,使
得 Java SE 9 发布日期多次推后,终于在 2017 年 9 月 21 日正式发布。
可以在下面的页面中,看到 Java 模块平台系统一度被否决的投票结果:
http://jcp.org/en/jsr/results?id=5959
1.1.2 三大平台
在 Java 发展的过程中, 由于其应用领域越来越广, 并逐渐扩展至各级应用软件的开发, Sun
公司在 1999 年 6 月美国旧金山举办的 Java One 大会上,公布了新的 Java 体系架构。该架构根
据不同级别的应用开发区分了不同的应用版本: J2SE(Java 2 Platform, Standard Edition)、
J2EE(Java 2 Platform, Enterprise Edition)与 J2ME(Java 2 Platform, Micro Edition)。
J2SE、 J2EE 与 J2ME 是当时的名称,由于 Java SE 6 后 Java 不再带有 2 这个号码, J2SE、
J2EE 与 J2ME 分别被正名为 Java SE、 Java EE 与 Java ME。
尽管 Sun 2006 年底,就将三大平台正名为 Java SE Java ME Java EE ,但时至今日,
许多人的习惯并没有改过来,
J2SE J2ME J2EE 这些名词还是有很多人用。
1. Java SE
Java 是各应用平台的基础,想要学习其他的平台应用,必先了解 Java SE 以奠定基础,而
Java SE 也正是本书主要的介绍对象。
图 1.2 所示是整个 Java SE 的组成概念图。

图 1.2 Java SE 的组成概念图
Java SE 可以分为四个主要的部分: JVM、 JRE、 JDK 与 Java 语言。
为了能够运行 Java 撰写好的程序,必须有 Java 虚拟机(Java Virtual Machine, JVM)。 JVM
包括在 Java 执行环境(Java SE Runtime Environment, JRE)中,所以要运行 Java 程序,必须
先安装 JRE。 如果要开发 Java 程序, 必须取得 JDK(Java SE Development Kits), JDK 包括 JRE
及开发过程中需要的一些工具程序,如 javac、 java 等工具程序(关于 JRE 及 JDK 的安装与使用
方法,会在第 2 章说明)。
Java 语言只是 Java SE 的一部分,除此以外,Java 最重要的就是提供庞大且强大的标准 API,
提供字符串处理、数据输入/输出、网络套件、用户窗口接口等功能,可以使用这些 API 作为基
础来进行程序开发,无须重复开发功能相同的组件。事实上,在熟悉 Java 语言之后,更多的时
候,都是在学习如何使用 Java SE 提供的 API 来完成应用程序。
2. Java EE
Java EE 以 Java SE 为基础,定义了一系列的服务、 API、协议等,适用于开发分布式、多
层次(Multi-tiered)、以组件为基础、以 Web 为基础的应用程序。整个 Java EE 的体系是相当庞
大的,比较为人熟悉的技术是 JSP、 Servlet、 JavaMail、 Enterprise JavaBeans(EJB)等,其中每个
服务或技术都可以使用专书进行说明,并非本书说明的范围。但可以肯定的是,必须在 Java SE
上奠定良好的基础,再来学习 Java EE 的开发。
3. Java ME
Java ME 是 Java 平台版本中最小的应用程序,目的是作为小型数字设备上开发及部署应用
程序的平台,如消费性电子产品或嵌入式系统等,其中最为人熟悉的设备如手机、 PDA、股票
机等。可以使用 Java ME 来开发出这些设备上的应用程序,如 Java 游戏、股票相关程序、记事
程序、日历程序等。
1.1.3 JCP 与 JSR
Java 不仅是程序语言,还是标准规范。
先来看看没有标准会产生什么问题?我们的身边有些东西没有标准,例如手机充电器,不
同厂商的手机,充电器也不相同,家里面一堆充电器互不相容,换个手机,充电器就不能用的
情况,相信你我都有过。
有标准的好处是什么?现在许多计算机外部设备,都采用 USB 作为传输接口,这让计算机
中不用再接上一些转接器,跟过去计算机主机后面一堆不同规格的传输接口相比,实在方便了
不少,现在许多手机的充电器,也改采用 USB 接口了,这真是件好事。
回头来谈谈 Java 是标准规范这件事。 你知道吗?编译/执行 Java 的 JDK/JRE, 并不只有 Sun
才能实现, IBM 也可以撰写自己的 JDK/JRE,其他厂商或组织也可以撰写自己的 JDK/JRE,你
写的 Java 程序,可以执行在这些不同厂商或组织写出来的 JRE 上。第 2 章将学到的第一个 Java
程序,其中会有这么一段程序代码:
System.out.println("Hello World");
这行程序目的是:请系统(System)的输出装置(out)显示一行(println)Hello World。是谁决定
使用 System、 out、 println 这些名称的?为什么不是 Platform、 Output、 ShowLine 这些名称?
如果 Sun 使用 System、 out、 println 这些名称,而 IBM 使用了 Platform、 Output、 ShowLine 这
些名称, 用 Sun 的 JDK 写的程序, 就不能执行在 IBM 的 JRE 上, 那 Java 最基本的特性之一“跨
平台”,就根本无法实现了。
Java 由 Sun 创造,为了让对 Java 感兴趣的厂商、组织、开发者与用户参与定义 Java 未来
的功能与特性, Sun 公司于 1998 年组成了 JCP(Java Community Process),这是一个开放性国
际组织,目的是让 Java 的演进由 Sun 非正式地主导,成为全世界数以百计代表成员公开监督
的过程。
任何想要提议加入 Java 的功能或特性,必须以 JSR(Java Specification Requests)正式文
件的方式提交, JSR 必须经过 JCP 执行委员会(Executive Committee)投票通过,方可成为最
终标准文件,有兴趣的厂商或组织可以根据 JSR 实现产品。
若 JSR 成为最终文件后,必须根据 JSR 做出免费且开发原始码的参考实现,称为 RI(Reference
Implementation),并提供 TCK(Technology Compatibility Kit)作为技术兼容测试工具箱,方
便其他想根据 JSR 实现产品的厂商或组织参考与测试兼容性。 JCP、 JSR、 RI 与 TCK 的关系,
如图 1.3 所示。

Java 平台概论 1

图 1.3 JCP、 JSR、 RI 与 TCK
JCP 官方网站为 http://jcp.org
现在无论 Java SE、 Java EE 还是 Java ME,都是业界共同制定的标准,每个标准背后都隐
藏着业界所面临的一些问题,他们期待使用 Java 来解决问题,认为应该有某些组件、特性、应
用程序编程接口等,来解决这些问题,因而制定 JSR 作为正式标准规范文件,不同的技术解决
方案标准规范会给予一个编号。
在 JSR 规范的标准之下,各厂商可以各自操作成品,所以同一份 JSR,可以有不同厂商的
操作产品。以 Java SE 为例,对于身为开发人员,或使用 Java 开发产品的公司而言,只要使用
兼容于标准的 JDK/JRE 开发产品,就可以执行、兼容在标准的 JRE 上,而不用担心跨平台的
问题。
Java SE 9 的主要规范是在 JSR 379 文件之中,而 Java SE 9 平台中的特定技术,则规范于特
定的 JSR 文件之中。若有读者对这些文件有兴趣,可以参考 JSR379,网址如下:
http://jcp.org/en/jsr/detail?id=379
想要查询 JSR 文件,只要在 http://jcp.org/en/jsr/detail?id= 之后加上文件编号就可以了,
例如上面查询
JSR 379 文件网址就是:
http://jcp.org/en/jsr/detail?id=379
JSR
对于 Java 初学者而言过于生涩,但 JSR 文件规范了相关技术应用的功能,将来有能
力时,可以试着自行阅读
JSR ,这有助于了解相关技术规范的更多细节。
1.1.4 Oracle JDK 与 OpenJDK
在过去, Sun JDK 实现,也就是被 Oracle 收购之后的 Oracle JDK 实现,就是 JDK 的参考
实现,有兴趣的厂商或组织也可以根据 JSR 自行实现产品,例如 IBM 就是根据 JSR 实现了自
家的 IBM JDK。 只有通过 TCK 兼容性测试的实现,才可以使用 Java 这个商标。
IBM JDK http://www.ibm.com/developerworks/java/jdk/
2006 年的 JavaOne 大会上, Sun 宣告对 Java 开放源代码,从 JDK7 b10 开始有了
OpenJDK,并于 2009 年 4 月 15 日正式发布 OpenJDK。 Oracle 时代发布的 JDK7 正式版本,
指定了 OpenJDK7 为官方参考实现。
1. Oracle JDK7
OpenJDK7
与同为开放源代码的 Sun JDK 不同的是,Sun JDK 采用 JRL,而 OpenJDK7 采用 GPL(带

有GPL linking exception 的修正版本),前者源代码可用于个人研究使用,但禁止任何商业
用途,后者则允许商业使用。因此, OpenJDK7 必须删掉许多在两个授权间有冲突的程序代码,
也不包括一些部署(Deployment)工具(例如 Java Web Start 等)以及软件套件(例如 Java DB)等;现
在你在 Java Platform, Standard Edition 7 Reference Implementations(或 Java Platform, Standard
Edition 9 Reference Implementations)下载 RI 时,也会看到有基于 GNU General Public License
version 2 与 Oracle Binary Code License 两个授权的版本。
Java Platform, Standard Edition 7 Reference Implementations
http://jdk.java.net/java-se-ri/7
Java Platform, Standard Edition 9 Reference Implementations

http://jdk.java.net/java-se-ri/9
由于 OpenJDK7 中有许多程序代码因授权冲突而必须删掉,因此原始的 OpenJDK7 是不完
整的,所以无法通过 TCK 兼容测试。 如果执行
java -version ,原始的 OpenJDK7 显示的会
是 openjdk version 字样,而不是 java version 字样。
为了解决授权问题, 以便在 Fedora 或 Linux 分支中能自由发布 OpenJDK7, Red Hat 于 2007
年发起了 IcedTea 计划。而由于原始的 OpenJDK7 是不完整的,后来 IcedTea 致力于修补
OpenJDK7 使之完备,并通过了 TCK 兼容测试。 如果使用 IcedTea 修补过后的 OpenJDK7,
执行
java -version ,就会显示 java version 字样。
2. OpenJDK7
OpenJDK6
在 OpenJDK 官方网站,也可以看到 OpenJDK6 的版本, OpenJDK6 并不是 Sun JDK6 的
分支,而是将 OpenJDK7 中 JDK7 的特性删掉,使之符合 JDK6 的规范,因而 OpenJDK6 实际
上是 OpenJDK7 的分支, OpenJDK6 可以通过 TCK 兼容测试。
Oracle 从 2012 年 7 月以来,就打算结束对 JDK6 的支持,在 2013 年 2 月时发布 JDK6 Update
43 时,宣布这是最后一个免费更新版本(实际上后来还有 Update 45),希望大家赶快升级至
JDK7。
由于 JDK6 在企业间仍广泛应用, Red Hat 于 2013 年 3 月宣布持有 OpenJDK6 领导权,
以便能持续对 OpenJDK6 发现的漏洞与安全问题进行修补。
1.1.5 建议的学习路径
Java 不仅是程序语言,还是标准规范。每个标准代表着厂商面临的问题,代表着解决问题
的方案,因此,学习 Java 就等于在面临各式问题如何解决。然而,这么多的问题衍生出如此多
的解决方案,对于初学 Java 的人而言,如同面临满载产品的庞大货轮,不知从何开始,也不知
将来何去何从。
如果将程序语言比喻为一艘船,会是如何呢?这里有篇有趣的文章:
http://compsci.ca/blog/if-a-programming-language-was-a-boat/
Java 的官方网站提供了一份 Java 技术概念地图(Java Technology Concept Map)的文件, 如图
1.4 所示。这是份 PDF 文件,可以在以下网址下载:
http://www.oracle.com/technetwork/topics/newtojava/intro-142494.html

图 1.4 Java 技术概念地图
Oracle 合并 Sun 之后, Java 的官方网站是:
http://java.oracle.com/
连接网络之后,将会被重新链接至:
http://www.oracle.com/technetwork/java/index.html
在这份文件中,密密麻麻地列出了大部分 Java 相关地图与简要说明,也代表了 Java 技术
范畴的广泛。然而要从这么庞大的地图中找出一条适合初学 Java 的路线图绝非易事。以下是我
基于经验与教学建议的学习路径。
1. 深入了解 JVM/JRE/JDK
许多书籍对于 JVM/JRE/JDK 的说明,通常只用了极短的篇幅介绍,就是在短短几页中,
请使用者按书中步骤安装与设定
PATH CLASSPATH 后,就开始介绍 Java 程序语言。而许多人到
了业界后就开始使用 IDE(Integrated Development Environment)代劳所有 JDK 细节。这么做的结
果就是,在 IDE 中遇到与 JDK 相关的问题,就完全不知道如何解决。
JVM/JRE/JDK 并不是用短短几页就可以说明,若没有“JVM 是 Java 程序唯一认识的操作
系统,其可执行文件为.class 文档”的重要观念,就无法理解
PATH CLASSPATH 并非同一层级
的 环 境 变 量 , JDK 中 许 多 指 令 与 选 项 其 实 都 可 以 对 应 至 IDE 中 某 个 设 定 与 操 作 。 对
JVM/JRE/JDK 有了足够的认识,对 IDE 中相关选项就不会有疑问,也不会换个 IDE 就不知所
措,或没有 IDE 就无法撰写程序。
2.
理解 封装、继承、多态
对于 Java 程序语言,
if...else for while switch 等流程语法早已是必须熟练的基础。
更重要的是, Java 支持面向对象(Object Oriented),你必须理解面向对象中最重要的封装
(Encapsulation)、 继承(Inheritance)、 多态(Polymorphism)概念,以及如何用 Java 相关语法来
实现。
许多人撰写 Java 程序,并没有善用其支持面向对象的特性,问到何谓封装却无法回答(甚
至回答定义类即为封装),滥用 Java 继承语法,不懂多态而不知如何运用 API 文件,更别说运
用多态设计程序了,最后的结果就是沦于死背 API 文件、使用“复制、粘贴”大法来撰写程序,
整个应用程序架构杂乱无章且难以维护。
3. 掌握常用 Java SE API 架构
Java 并非只是程序语言,还带有庞大的各式链接库(Library),对初学者而言,首要是掌握
常用的 Java SE API, 例如异常(Exception)、集合(Collection)、输入/输出串流(Stream)、线程(Thread)
等。学习这些标准 API,应先掌握 API 在设计时的封装、 继承、 多态架构。 以
Collection
为例,在学习时必须先理解为何要设计如图 1.5 所示的架构。
产生

图 1.5 Collection API 架构范例
学习相关链接库或 API,先理解主要架构是有必要的,这样才不会沦于死背 API 或抄写范
例的窘境。更进一步地,还可以从 API 中学习到良好设计的观念,有了这样的好习惯,以后对
新的 API 或链接库就能更快地掌握如何使用甚至改进。
深入了解 JVM/JRE/JDK ,理解封装、继承、多态,掌握常用 Java SE API 架构,这都是
本书的说明重点。
4. 学习容器观念
在步入 Java EE 领域之后,经常接触到容器(Container)的观念,许多人完全以 API 层次来
使用 Java EE 相关组件,这是不对的。就操作层面来说,容器是执行于 JVM 上的 Java 应用程
序;从抽象层面来说,就是应用程序沟通、协调相关资源的系统。
初次接触容器的开发人员会觉得容器很抽象。以实际的例子来说,通常初学者步入 Java EE,
会从学习 Servlet/JSP 开始,而 Servlet/JSP 是执行于 Web 容器之中,这是学习容器时不错的开始,
你必须知道“Web 容器是 Servlet/JSP 唯一认识的 HTTP 服务器 ,是使用 Java 撰写的应
用程序,运行于 JVM 之上” 。如果希望用 Servlet/JSP 撰写的 Web 应用程序可以正常运作,
就必须知道 Servlet/JSP 如何与 Web 容器沟通, Web 容器如何管理 Servlet/JSP 的各种对象等
问题。
关于 Servlet/JSP 的说明,可参考我撰写的《 JSP & Servlet 学习笔记 ( 2 ) ( 清华大学
出版社
) ,或是 Servlet/JSP 在线文件:
http://openhome.cc/Gossip/ServletJSP/
容器无所不在, Applet 会执行于 Applet 容器中, 因此相关资源受到 Applet 容器的管理与限制,
Servlet/JSP 执行于 Web 容器中, EJB 执行于 EJB 容器中, Java 应用程序客户端执行于应用程序客
户端容器中,如图 1.6 所示。不理解组件如何与容器互动,就无法真正使用或理解组件的行为。

图 1.6 程序组件及其执行容器(摘自 https://docs.oracle.com/javaee/6/tutorial/doc/bnacj.html)
5. 研究开放原始码项目
Java 不仅是程序语言,也是个标准,在共同标准下有不同的运行方式,在 Java 领域的许多
操作都是以开放原始码的方式存在, 只要你有兴趣, 可以下载原始码了解运行方式, 从中了解、
吸收他人设计、实现产品的技巧或理念。
许多基于 Java 各标准平台发展出来的产品也值得研究,如测试框架(Framework)、 Web 框
架、持久层(Persistance)框架、对象管理容器等,这些产品补足标准未涵盖之处,各有其设计上
的优秀与精良之处,有的已成为 Java 标准之一,它们多以开放原始码的方式存在,让开发人员
可以使用、研究甚至参与改进。
想要开始研究开放原始码项目的使用与设计, JUnit 是个不错的开始,可以参考在线文件:
http://openhome.cc/Gossip/JUnit/
6. 学习设计模式 重构
在程序设计上,“经验”是最重要的,在经验传承上,归纳而言,无非就是“如何根据需
求做出好的设计”“如何因应需求变化调整现有程序架构”,对于前者,流传下来的设计经验就
是设计模式(Design Pattern),对于后者,流传下来的调整手法就是重构(Refactor)。
“如果我当初就这么设计,现在就不会发生这个问题了!”这种对话应该很熟悉,“当初就
这么设计”就是所谓设计模式。“如果我当初先这么改,再那么改,就不会把程序改到烂了!”
这种对话也经常听到,“当初先这么改,再那么改”就是所谓重构。
无论好的设计还是不好的设计,都要有经验传承。经验可以口耳相传,可以从原始码中观
摩,也可以从书籍或网络上优秀的技术文件中学得。对于初学者,从书籍或网络上优秀的技术
文件学习设计模式与重构,是积累经验的快捷方式。
7. 熟悉相关开发工具
除了累积足够的实力与基础,善用工具是必要的,开发工具可以避免烦琐的指令、减少重
复性的操作、提示可用的 API、自动产生程序代码、降低错误的发生,甚至执行各种自动化的
测试、报告产生与发送邮件等任务。有些开发人员鄙视开发工具,这是不必要的,两个实力相
同的开发人员撰写相同的应用程序,使用良好开发工具的人必然有较高的效率。
在 Java 领域难能可贵的是,存在不少优秀的开发工具,而且多以开放架构、开放原始码的
方式存在,如 Eclipse IDE、 NetBeans IDE、 IntelliJ IDEA 都是相当不错的选择。还可以搭配 Ant
构建工具、 Maven 或 Gradle 项目工具等一起使用,大大地提升开发人员的产能。
建议初学 Java 的人,可以挑选一种开发工具来熟悉。所谓熟悉,不是指“下一步要按哪个
按钮、接下来要执行哪个菜单”,而是指这些开发工具相关操作是为了代劳你手动执行哪些指
令, 开发工具中的某些选项是为了代劳你设定哪些变量, 错误提示原本是来自 JDK 的什么信息,
等等。以这样的过程来熟悉开发工具,才能善用开发工具提升产能,而不是受制于开发工具,
这样即便换了另一套开发工具,也可以在最短时间内上手。
本书会使用 NetBeans IDE IDE 中的操作、设定与 JDK 指令的对照,是本书的重点之一。
1.2 JVM/JRE/JDK
本书一开始曾说,不要只从程序语言的角度来看 Java,这只会看到“冰山一角”。这可以
用图 1.7 来印证。

图 1.7 Java 产品概念图(摘自 http://www.oracle.com/technetwork/java/javase/tech/index.html)
如果安装 JDK,就会安装图中所示全部的东西,而 Java Language 只是最左上角一小部分。
如果只是用短短几页告诉你如何安装 JDK、设定环境变量,而不解释到底 JVM、 JRE 与 JDK
的作用与关系,你觉得够吗?
1.2.1 什么是 JVM
在图 1.7 中, Java Virtual Machine(JVM)会架构在 Linux、 Windows、 iOS 各种操作系统
平台之上。许多 Java 的书都会告诉你, JVM 让 Java 可以跨平台,但是跨平台是怎么一回事,
在这之前,得先了解不能跨平台是怎么一回事。
对于计算机而言,只认识一种语言,也就是 、 1 序列组成的机器指令。当使用 C/C++等
高级语言撰写程序时,其实这些语言是比较贴近人类可阅读的文法,也就是比较接近英语文法
的语言。这是为了方便人类阅读及撰写,计算机其实看不懂 C/C++这类语言,为了将 C/C++翻
译为 、 1 序列组成的机器指令,必须有个翻译员。担任翻译员工作的就是编译 程序
(Compiler),如图 1.8 所示。

图 1.8 编译程序将程序翻译为机器码
问题在于,每个平台认识的 、 1 序列并不一样。某个指令在 Windows 上也许是 0101,在
Linux 下也许是 1010,因此必须使用不同的编译程序为不同平台编译出可执行的机器码,在
Windows 平台上编译好的程序,不能直接拿到 Linux 等其他平台执行。也就是说,应用程序无
法达到“编译一次,到处执行” 的跨平台目的,如图 1.9 所示。
Windows
编译程序
Windows
编译程序
Windows
编译程序
Windows
Linux
Mac OS
Mac OS

图 1.9 使用特定平台编译程序翻译出对应的机器码
Java 是个高级语言, 要让计算机执行所撰写的程序, 需要通过编译程序的翻译。 不过用 Java
编译时,并不直接编译为相依于某平台的 、 1 序列,而是翻译为中介格式的位码(Byte Code)。
Java 原始码扩展名为.java,经过编译程序翻译为扩展名为.class 的位码。如果想要执行位
码文档,目标平台必须安装 JVM(Java Virtual Machine)。 JVM 会将位码翻译为相依于平台的机
器码,如图 1.10 所示。

不同的平台必须安装专属该平台的 JVM。这就好比你讲中文(*.java), Java 编译程序帮你翻
译为英语(*.class),这份英语文件到各个国家之后,再由当地看得懂英文的人(JVM)翻译为当地
语言(机器码)。
所以 JVM 担任的职责之一就是
当地翻译员,将位码文档翻译为当时
平台看得懂的 、 1 序列。有了 JVM,
你的 Java 程序就可以达到“编译一
次,到处执行” 的跨平台目的。除
了了解 JVM 具有让 Java 程序跨平台
的重要任务之外,在撰写 Java 程序
时,对 JVM 的重要认知就是:
对 Java 程序而言,只认识一
种操作系统,这个系统叫 JVM,
位码文档(扩展名为.class 的文档)
就是 JVM 的可执行文件。
Java 程序理想上并不用理会真正执行于哪个平台,只要知道如何执行于 JVM 就可以了。
至于 JVM 实际上如何与底层平台沟通,则是 JVM 自己的事。由于 JVM 实际上就相当于 Java
程序的操作系统, JVM 就负责了 Java 程序的各种资源管理。
了解“ JVM 就是 Java 程序的操作系统, JVM 的可执行文件就是 .class 文档”非常重要,
对于以后理清所谓
PATH 变量与 CLASSPATH 变量之间的差别,有非常大的帮助。
1.2.2 区分 JRE 与 JDK
这里再看一下第 2 章将学到的第一个 Java 程序,其中会有这么一段程序代码:
System.out.println("Hello World");
前面曾经谈过, Java 是个标准, System、 out、 println 都是标准中规范的名称。实际上必须
要有人根据标准撰写出 System.java, 编译为 System.class, 这样这些名称才能在撰写第一个 Java
程序时,使用
System 类(Class)上 out 对象(Object)的 println() 方法(Method)。
谁来操作 System.java?谁来编译为.class?可能是 Oracle、 IBM、 Apache,无论如何,这些
厂商必须根据相关的 JSR 标准文件将标准链接库开发出来,这样撰写的第一个 Java 程序,在
Oracle、 IBM、 Apache 等厂商开发的 JVM 上运行时,引用如
System 这些标准 API,才可能轻
易地运行在不同的平台。
在图 1.7 中右侧部分可以看到 Java SE API 涵盖了各式常用的链接库,像是通用的集合
(Collection)、输入/输出、联机数据库的 JDBC、撰
写窗口程序的 Java FX 等,这些都是在各个 JSR 标
准文件规范之中。
Java Runtime Environment 就是 Java 执行环
境, 简称 JRE, 包括 Java SE API 与 JVM。只要
使用 Java SE API 中的链接库,在安装有 JRE 的计
算机上就可以直接运行,无须额外在程序中再包装
链接库,而可以由 JRE 直接提供,如图 1.11 所示。

图 1.11 JRE 包括 Java SE API 与 JVM
java
编译程序
位码

Windows
Linux
Mac

在图 1.7 中还可以看到,实际上 JRE 还包括了部署 (Deployment) 技术,也就是如何将程
序安装到客户端的技术,不过这不在本书介绍范围内。建议直接查看图
1.7 摘自的网址,
其中有各种主题的文件说明,可以善加利用。
前面说过,要在.java 中撰写 Java 程序语言,使用编译程序编译为.class 文档,那么像编译
程序这样的工具程序是由谁提供?答案就是 JDK,全名为 Java Developer Killer!呃!不对!是
Java Development Kit!
正如图 1.7 所示, JDK 包括了 javac、 java、 javadoc 等工具程序,对于要开发 Java 程序的人,
必须安装的是 JDK, 这样才有这些工具程序可以使用, JDK 本身包括了 JRE, 这样才能执行 Java
程序,所以总结就是“JDK 包括了 Java 程序语言、工具程序与 JRE, JRE 则包括了部署
技术、 Java SE API 与 JVM” ,这也就是图 1.2 想表达的含义。
撰写 Java 程序才需要 JDK,如果你的程序只是想让朋友执行呢?那他只要装 JRE 就可以
了,不用安装 JDK,因为他不需要 javac 这些工具程序,但他需要 Java SE API 与 JVM。
对初学者来说, JDK 确实很不友善,这大概是 Java 阵营的哲学,它会假设你懂得如何准备
相关开发环境,因此装好 JDK 之后,该自己设定的变量或选项就要自己设定, JDK 不会代劳,
过去戏称 JDK 全名为 Java Developer Killer 其实是有其来源的。
了解 Java SE 中 JVM、 JRE 与 JDK 的关系之后,接下来应该来点实际操作了。第一步就是
下载、安装 JDK。
1.2.3 下载、安装 JDK
要下载 JDK,请链接到(Java SE Downloads)以下网址:
http://www.oracle.com/technetwork/java/javase/downloads/index.html
你要下载的是 Java SE 9 中的 JDK,按照以往惯例,发布 JDK 之后,每隔几个月会针对使
用者反馈的 BUG 或安全问题进行修正,并发布一个修正版 JDK。在过去,如果你连接以上网
址时,出现的字样是 Java SE Development XuN 之类的字样,其中 X 会是重大特性发布用的号
码,像是 8、 9 等号码,也就是代表 Java SE 8、 Java SE 9 等, N 就是 BUG 或安全问题更新版本
号。图 1.12 所示为 JDK 的下载页面。

图 1.12 JDK 下载页面
然而, Oracle 在 Oracle Java SE Support Roadmap 中提出了新的特性版本发布方式,不再是
基于重大特性来发布版本,而是改为基于时间、以半年为周期、持续发布小特性的版本,让一
些对开发者有用的小特性,可以在这些新版本中放出,而这些版本将会是短期支持版本,在下
个小特性版本发布之后,上个版本就不再维护,使用者要赶快更新至新版本。
有些语言也是持续而频繁地发布新版本,比如 Go 语言,基于时间而非基于重大特性来发布
的软件,最典型的范例就是
Ubuntu
除了短期支持版本之外,
Oracle 也有 Java SE 的长期支持版本,基本上以 3 年为周期,可以
通过
Oracle Java SE Advanced Oracle Java SE Advanced Desktop Java SE Suite 取得。另
外,
Java SE 8 会是个长期支持版本, 将支持至 2022 年, 详情可以参考 Oracle Java SE Support
Roadmap
中的说明: http://www.oracle.com/us/technologies/java/eol-135779.html
虽然未来 JDK 在小特性版本发布时,预计采用 $YEAR.$MONTH 格式,不过看来尚有讨论空
间,详情可看:
mail.openjdk.java.net/pipermail/jdk-dev/2017-October/000007.html
在网页中还可以看到 Server JRE 与 JRE 的下载。前面提过,用户如果要执行 Java 程序,只
需要安装 JRE,不需要安装 JDK,其中客户端应用程序可以下载 JRE 版本,如果是要运行服务
器端应用程序,可以下载 Server JRE 版本。
单击 JDK 的 Download 按钮,会进入另一个页面。必须先选中 Accept License Agreement(同
意许可协议)单选按钮,接着选择对应操作系统版本的 JDK。以 Windows x64 为例,单击
jdk-9_windows-x64_bin.exe 就可以下载 JDK,如图 1.13 所示。

图 1.13 开始下载 JDK
下载完成后,双击文档就可以看到启始安装画面,直接单击“下一步”按钮看到图 1.14 所
示对话框。
开发工具(Development Tools)就是安装编译程序之类的工具程序,要开发 Java 程序,就
得安装它。源代码 (Source Code)是 JRE 中 Java SE API 的操作程序代码,有时候,你会需要查
看 Java SE API 原始码,了解一下内部运作机制。公共 JRE(Public JRE)就是刚刚在图 1.12
中看到的 JRE,所以下载了 JDK,就同时下载了 JRE。
除了“开发工具”之外,另外两个选项,其实都可以不安装,这不影响后续的程序开发。
不过为了以后可以参考一些原始码、直接在“公共 JRE”上测试等,或开发简单的数据库程
序,建议选择“全部安装”选项。
不安装 Public JRE?那怎么执行写好的 Java 程序呢?不是说要有 JRE 才可以执行吗?其实
JDK 本身附有一个 JRE,相对于 Public JRE 这个名称,JDK 自己附的 JRE 通常称为 Private JRE,
只要安装 JDK,一定就有 Private JRE,稍后会说明 Private JRE 的安装位置。安装 Public JRE 或
自行下载 JRE 安装,会注册 Java Plugin、 Web Start 等浏览器或桌面客户端必要的元件,方便需
要 JRE 的应用程序使用。
在安装时注意图 1.14 中“安装到”的位置,必须记住 JDK 安装位置,之后设定
PATH 变量
时会用到这个信息。单击图 1.14 中的“下一步”按钮,等待 JDK 安装完后,若在图 1.14 中选
择安装“公共 JRE”,就会再出现安装 Public JRE 的画面,同样地,请记下安装位置,如图 1.15
所示。

基于安全原因, Oracle 曾宣布将停止浏览器外挂:
http://blogs. oracle.com/java-platform- group/ moving- to-a-plugin-free-web
就本章撰写期间,是否启用浏览器中的 Java 支持,这就交给使用者来决定,在台湾仍有
些金融机构会采用
Applet 来提供网络银行之类的服务,如果你没有这类需求,在图 1.15
中可以不选中“启用浏览器中的 Java 内容”复选框。
装好 JDK 之后,在 Windows 7 或 Windows 后续版本中,可以在“开始”菜单中执行“所
有程序” |“附件” |“命令提示符”命令,启动“命令提示符”窗口。在 Windows 10 中,可以
直接在“开始”界面输入 cmd 启动“命令提示字符”,接着输入 java,看到图 1.16 所示界面,
表示 JDK 初步安装完成。

图 1.16 查看 JDK 是否安装完成
为什么说 JDK 初步安装完成?因为还要设定 PATH 环境变量, 这要在第 2 章中再做说明。
1.2.4 认识 JDK 安装内容
那么你到底安装了哪些东西呢?假设 JDK 与 Public JRE 各安装至 C:\Program Files\Java\jdk-
9.0.4\及 C:\Program Files\Java\jre-9.0.4(如果安装时有选择“公共 JRE”选项的话)。
Public JRE 是给 Java 程序执行的平台, JDK 本身也附带 JRE,通常被称为 Private JRE。如
果你熟悉 Java SE 8 或者之前版本的 Java,可能会想 Private JRE 应该还是在 JDK 安装文件夹中
的 jre 文件夹中。不过, Java SE 9 改变了 JDK 与 Public JRE 的文件夹内容, JDK 安装文件夹中
没有专用的 jre 文件夹来放 Private JRE 了,只要记得 JDK 文件夹中包含 JRE 的内容就可以了(以
及 JVM)。除此之外,也看不到过去 JDK 版本安装后会有的 rt.jar 与 tools.jar。
图 1.17 中可以对照图 1.14 的部分, bin 文件夹中存放的就是 Development Tools,包括了
编译 Java 原始码的
javac ,执行 Java 程序的 java 等工具程序。

图 1.17 JDK 安装文件夹
至于 Source Code 选项,也就是 Java SE API 运行原始码的部分,可以在 lib 文件夹中的 src.zip
中找到,使用解压缩软件解开,就能看到许多文件夹,它们对应至 Java SE 9 的模块平台系统划
分出来的各个模块,而在这些文件夹中会有许多.java 原始码文档。
那么 Java SE API 编译好的.class 文档放在哪里呢? Java SE 9 的模块平台系统为了改进效
率、安全与维护性,使用了模块执行时期映像(Modular Run-Time Images),又称 JIMAGE,无
论是 JDK 或 Public JRE 的文件夹中, 都会有个 lib 文件夹, 其中有个 modules 文档, 包含了.class
文档的执行时期格式。
可以使用 jlink 来建立专用的执行时期映像,其中只包含你使用到的模块, 19.3 节会介绍这
些模块如何建立;
modules 文档中的 .class 文档是可以取出的,如果有兴趣的话,可以查看
下 面 的 链 接 :
http://blogs.oracle.com/sundararajan/extracting-a-single-class-file-from-ava9-
platform-jimage-modules-file
至于在编译时期, Java SE 9 引入了新的 JMOD 格式来封装模块,扩展名为.jmod,这些文
档位于 JDK 文件夹中的 jmods 文件夹,每个模块对应的.jmod 中就包括了编译完成的.class 文档。
在过去, JAR(Java Archive) 文档是封装 .java .class 文档的主要格式,有许多开发工具
都能自动为用户建立
JAR 文档,而在文本模式下,还可以使用 JDK jar 工具程序来制
JAR 档案, 19.3 节会介绍如何使用 jar 工具程序。
JMOD 格式可以包含比 JAR 文档更多的信息,如原生指令、链接库等, JDK9 本身包含
jmod 工具程序,可以用来建立 JMOD 文档,或者从 JMOD 文档中取得封装的内容 (
前实际上只是
ZIP 压缩,然而未来可能改变 ) 19.3 也会介绍如何使用 jmod 工具程序。
你可以回头对照图 1.7,问问自己,现在是不是记住 JDK、 JRE、 Java SE API 与 JVM 的安
装位置了呢?
因为 Java SE 9 JDK/JRE 在文档实体布局上,有别于过去的 Java SE 版本,如果你曾
在旧版
JDK 上使用相关开发工具撰写过 Java 程序,在升级至 Java SE 9 之后,相关开发
工具可能会因此而在执行上有问题,若是如此,请确认你的开发工具是否有针对
JDK9
的升级版本。
1.3 重点复习
Java 最早是 Sun 公司“绿色项目” (Green Project)中撰写 Star7 应用程序的程序语言,当时
名称不是 Java,而是取名为 Oak。全球信息网兴起, Java Applet 成为网页互动技术代表。 1995
年 5 月 23 日,正式将 Oak 改名为 Java, Java Development Kits(当时的 JDK 全名)1.0a2 版本正式
对外发表。
Java 2 名称从 J2SE 1.2 一直沿用至之后各个版本,直到 2006 年 12 月 11 日的 Java Platform,
Standard Edition 6,改称 Java SE 6, JDK6 全名则称为 Java SE Development Kit 6,也就是不再
像 Java 2 带有 2 这个号码。
2010 年, Oracle 宣布并购 Sun, Java 正式成为 Oracle 所属。
Java 根据应用领域不同,区分为 Java SE、 Java EE 与 Java ME 三大平台。 Java SE 是各应用
平台的基础,分为四个主要的部分: JVM、 JRE、 JDK 与 Java 语言。 JDK 包括 Java 程序语言、
JRE 与开发工具, JRE 包括 Java SE API 与 JVM。
JCP 是个开放性国际组织,目的是让 Java 演进由 Sun 非正式地主导,成为全世界数以百计
代表成员公开监督的过程。任何想要提议加入 Java 的功能或特性,必须以 JSR 正式文件的方式
提交,经过 JCP 执行委员会投票通过,方可成为最终标准文件,有兴趣的厂商或组织可以根据
JSR 实现产品。
若 JSR 成为最终文件后,必须根据 JSR 成果做出免费且开发原始码的参考实现,称为
RI(Reference Implementation), 并提供 TCK(Technology Compatibility Kit)作为技术兼容测试工具
箱,方便其他想根据 JSR 实现产品的厂商或组织参考与测试兼容性。
只有通过 TCK 兼容性测试的实现,才可以使用 Java 这个商标。
在 2006 年的 JavaOne 大会上,Sun 宣告对 Java 开放源代码,从 JDK7 b10 开始有了 OpenJDK,
并于 2009 年 4 月 15 日正式发布 OpenJDK。Oracle 时代发布的 JDK7 正式版本,指定了 OpenJDK7
为官方参考实现。
OpenJDK6 并不是 Sun JDK6 的分支,而是将 OpenJDK7 中 JDK7 的特性删掉,使之符合 JDK6
的规范,因而 OpenJDK6 实际上是 OpenJDK7 的分支。
Java 编译时并不直接编译为相依于某平台的 、 1 序列,而是翻译为中介格式的位码(Byte
Code)。对 Java 程序而言,只认识一种操作系统,这个系统叫 JVM,位码文档(扩展名为.class
的文档)就是 JVM 的可执行文件。
Java Runtime Environment 就是 Java 执行环境,简称 JRE,包括 Java SE API 与 JVM。只要
使用 Java SE API 中的链接库,在安装有 JRE 的计算机上就可以直接运行,无须额外在程序中
再包装链接库,而由 JRE 直接提供。
JDK 本身附有一个 JRE,相对于 Public JRE 这个名称,JDK 所附的 JRE 通常称为 Private JRE,
只要安装 JDK,一定就有 Private JRE。安装 Public JRE 或自行下载 JRE 安装,会注册 Java Plugin、
Web Start 等浏览器或桌面客户端必要的组件,方便需要 JRE 的桌面应用程序使用。

购买地址:

http://product.dangdang.com/25306459.html


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/26421423/viewspace-2217185/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
分享计算机前沿技术和国外计算机先进技术书籍。

注册时间:2011-11-08

  • 博文量
    54
  • 访问量
    106103