内容简介
《Java编程思想》:
从《Java编程思想》获得的各项大奖以及来自世界各地的读者评论中,不难看出本书是一本经典之作。《Java编程思想》的作者拥有多年教学经验,对C、C++以及Java语言都有独到、深入的见解,以通俗易懂及小而直接的示例解释了一个个晦涩抽象的概念。《Java编程思想》共22章,包括操作符、控制执行流程、访问权限控制、复用类、多态、接口、通过异常处理错误、字符串、泛型、数组、容器深入研究、JavaI/O系统、枚举类型、并发以及图形化用户界面等内容。这些丰富的内容,包含了Java语言基础语法以及高级特性,适合各个层次的Java程序员阅读,同时也是高等院校讲授面向对象程序设计语言以及Java语言的好教材和参考书。
《自己动手写JAVA虚拟机》:
Java虚拟机非常复杂,要想真正理解它的工作原理,好方式就是自己动手编写一个!
张秀宏编著的《自己动手写Java虚拟机》是继《深入理解Java虚拟机》之后的又一经典著作,它一方面遵循《Java虚拟机规范》,一方面又独辟蹊径,不仅能让Java虚拟机的学习变得更加简单和有趣,而且能让你对Java虚拟机的原理认识更深入和更深刻!
《自己动手写JAVA虚拟机》摒弃了传统的以解读枯燥的Java虚拟机规范文档和分析繁琐的Java虚拟机源代码的方式来讲解Java虚拟机,取而代之的是,以实践的方式,引导读者如何从零开始构建和实现一个Java虚拟机。整个过程不仅能让读者做到对Java虚拟机知其然而且知其所以然,还能屏蔽大量不必要的繁琐细节,体会到实现过程中的成就感,让学习过程更加轻松、愉悦和高效。更重要的是,这种方式能引导读者更深入地认识和掌握Java虚拟机的工作原理。
作者简介
Bruce Eckel,Mind View公司(www.MirldView.net)的总裁,该公司向客户提供软件咨询和培训。他是C++标准委员会拥有表决权的成员之一,拥有应用物理学学士和计算机工程硕士学位。除本书外,他还是《C++编程思想》的作者,并与人合著了《C++编程思想第2卷》(这两本书的英文影印版及中文版均已由机械工业出版社引进出版)及其他著作。他已经发表了150多篇论文,还经常参加世界各地的研讨会并进行演讲。
张秀宏,Java服务器开发工程师,有多年的Java开发、游戏服务器开发和架构经验,对Java虚拟机有非常深入的研究。曾在EA、华娱无线等游戏公司担任高级服务器工程师职位,现任乐元素Lead软件工程师。
内页插图
目录
《Java编程思想》:
出版者的话
专家指导委员会
读者评论
关于《Thinking in C++》
译者序
译者简介
前言
绪论
第1章 对象导论
1.1 抽象过程
1.2 每个对象都有一个接口
1.3 每个对象都提供服务
1.4 被隐藏的具体实现
1.5 复用具体实现
1.6 继承
1.6.1 “是一个”与“像是一个”关系
1.7 伴随多态的可互换对象
1.8 单根继承结构
1.9 容器
1.9.1 参数化类型(范型)
1.10 对象的创建和生命期
1.11 异常处理:处理错误
1.12 并发编程
1.13 Java与Internet
1.13.1 Web是什么
1.13.2 客户端编程
1.13.3 服务器端编程
1.14 总结
第2章 一切都是对象
2.1 用引用操纵对象
2.2 必须由你创建所有对象
2.2.1 存储到什么地方
2.2.2 特例:基本类型
2.2.3 Java中的数组
2.3 永远不需要销毁对象
2.3.1 作用域
2.3.2 对象的作用域
2.4 创建新的数据类型:类
2.4.1 字段和方法
2.5 方法、参数和返回值
2.5.1 参数列表
2.6 构建一个Java程序
2.6.1 名字可见性
2.6.2 运用其他构件
2.6.3 static 关键字
2.7 你的第一个Java程序
2.7.1 编译和运行
2.8 注释和嵌入式文档
2.8.1 注释文档
2.8.2 语法
2.8.3 嵌入式HTML
2.8.4 一些标签示例
2.8.5 文档示例
2.9 编码风格
2.10 总结
2.11 练习
第3章 操作符
3.1 更简单的打印语句
3.2 使用Java操作符
3.3 优先级
3.4 赋值
3.4.1 方法调用中的别名问题
3.5 算术操作符
3.5.1 一元加、减操作符
3.6 自动递增和递减
3.7 关系操作符
3.7.1 测试对象的等价性
3.8 逻辑操作符
3.8.1 短路
3.9 直接常量
3.9.1 指数记数法
3.10 按位操作符
3.11 移位操作符
3.12 三元操作符 if-else
3.13 字符串操作符 + 和 +=
3.14 使用操作符时常犯的错误
3.15 类型转换操作符
3.15.1 截尾和舍入
3.15.2 提升
3.16 Java没有sizeof
3.17 操作符小结
3.18 总结
第4章 控制执行流程
4.1 true和false
4.2 if-else
4.3 迭代
4.3.1 do-while
4.3.2 for
4.3.3 逗号操作符
4.4 Foreach语法
4.5 return
4.6 break和 continue
4.7 臭名昭著的goto
4.8 switch
4.9 总结
第5章 初始化与清理
5.1 用构造器确保初始化
5.2 方法重载
5.2.1 区分重载方法
5.2.2 涉及基本类型的重载
5.2.3 以返回值区分重载方法
5.3 默认构造器
5.4 this关键字
5.4.1 在构造器中调用构造器
5.4.2 static的含义
5.5 清理:终结处理和垃圾回收
5.5.1 finalize()的用途何在
5.5.2 你必须实施清理
5.5.3 终结条件
5.5.4 垃圾回收器如何工作
5.6 成员初始化
5.6.1 指定初始化
5.7 构造器初始化
5.7.1 初始化顺序
5.7.2 静态数据的初始化
5.7.3 显式的静态初始化
5.7.4 非静态实例初始化
5.8 数组初始化
5.8.1 可变参数列表
5.9 枚举类型
5.10 总结
第6章 访问权限控制
6.1 包:库单元
6.1.1 代码组织
6.1.2 创建独一无二的包名
6.1.3 定制工具库
6.1.4 用 import改变行为
6.1.5 对使用包的忠告
6.2 Java访问权限修饰词
6.2.1 包访问权限
6.2.2 public:接口访问权限
6.2.3 private: 你无法访问
6.2.4 protected:继承访问权限
6.3 接口和实现
6.4 类的访问权限
6.5 总结
第7章 复用类
7.1 组合语法
7.2 继承语法
7.2.1 初始化基类
7.3 代理
7.4 结合使用组合和继承
7.4.1 确保正确清理
7.4.2 名称屏蔽
7.5 在组合与继承之间选择
7.6 protected关键字
7.7 向上转型
7.7.1 为什么称为向上转型
7.7.2 再论组合与继承
7.8 final关键字
7.8.1 final 数据
7.8.2 final 方法
7.8.3 final 类
7.8.4 有关final的忠告
7.9 初始化及类的加载
7.9.1 继承与初始化
7.10 总结
第8章 多态
8.1 再论向上转型
8.1.1 忘记对象类型
8.2 转机
8.2.1 方法调用绑定
8.2.2 产生正确的行为
8.2.3 可扩展性
8.2.4 缺陷:“覆盖”私有方法
8.2.5 缺陷:域与静态方法
8.3 构造器和多态
8.3.1 构造器的调用顺序
8.3.2 继承与清理
8.3.3 构造器内部的多态方法的行为
8.4 协变返回类型
8.5 用继承进行设计
8.5.1 纯继承与扩展
8.5.2 向下转型与运行时类型识别
8.6 总结
第9章 接口
9.1 抽象类和抽象方法
9.2 接口
9.3 完全解耦
9.4 Java中的多重继承
9.5 通过继承来扩展接口
9.5.1 组合接口时的名字冲突
9.6 适配接口
9.7 接口中的域
9.7.1 初始化接口中的域
9.8 嵌套接口
9.9 接口与工厂
9.10 总结
第10章 内部类
10.1 创建内部类
10.2 链接到外部类
10.3 使用.this与.new
10.4 内部类与向上转型
10.5 在方法和作用域内的内部类
10.6 匿名内部类
10.6.1 再访工厂方法
10.7 嵌套类
10.7.1 接口内部的类
10.7.2 从多层嵌套类中访问外部类的
成员
10.8 为什么需要内部类
10.8.1 闭包与回调
10.8.2 内部类与控制框架
10.9 内部类的继承
10.10 内部类可以被覆盖吗
10.11 局部内部类
10.12 内部类标识符
10.13 总结
第11章 持有对象
11.1 泛型和类型安全的容器
11.2 基本概念
11.3 添加一组元素
11.4 容器的打印
11.5 List
11.6 迭代器
11.6.1 ListIterator
11.7 LinkedList
11.8 Stack
11.9 Set
11.10 Map
11.11 Queue
11.11.1 PriorityQueue
11.12 Collection和Iterator
11.13 Foreach与迭代器
11.13.1 适配器方法惯用法
11.14 总结
第12章 通过异常处理错误
12.1 概念
12.2 基本异常
12.2.1 异常参数
12.3 捕获异常
12.3.1 try块
12.3.2 异常处理程序
12.4 创建自定义异常
12.4.1 异常与记录日志
12.5 异常说明
12.6 捕获所有异常
12.6.1 栈轨迹
12.6.2 重新抛出异常
12.6.3 异常链
12.7 Java标准异常
12.7.1 特例:RuntimeException
12.8 使用finally进行清理
12.8.1 finally用来做什么
12.8.2 在return中使用finally
12.8.3 缺憾:异常丢失
12.9 异常的限制
12.10 构造器
12.11 异常匹配
12.12 其他可选方式
12.12.1 历史
12.12.2 观点
12.12.3 把异常传递给控制台
12.12.4 把“被检查的异常”转换为“不受
检查的异常”
12.13 异常使用指南
12.14 总结
第13章 字符串
13.1 不可变String
13.2 重载“+”与StringBuilder
13.3 无意识的递归
13.4 String上的操作
13.5 格式化输出
13.5.1 printf()
13.5.2 System.out.format()
13.5.3 Formatter类
13.5.4 格式化说明符
13.5.5 Formatter转换
13.5.6 String.format()
13.6 正则表达式
13.6.1 基础
13.6.2 创建正则表达式
13.6.3 量词
13.6.4 Pattern和Matcher
13.6.5 split()
13.6.6 替换操作
13.6.7 reset()
13.6.8 正则表达式与Java I/O
13.7 扫描输入
13.7.1 Scanner定界符
13.7.2 用正则表达式扫描
13.8 StringTokenizer
13.9 总结
第14章 类型信息
14.1 为什么需要RTTI
14.2 Class对象
14.2.1 类字面常量
14.2.2 泛化的Class引用
14.2.3 新的转型语法
14.3 类型转换前先做检查
14.3.1 使用类字面常量
14.3.2 动态的instanceof
14.3.3 递归计数
14.4 注册工厂
14.5 instanceof 与 Class的等价性
14.6 反射:运行时的类信息
14.6.1 类方法提取器
14.7 动态代理
14.8 空对象
14.8.1 模拟对象与桩
14.9 接口与类型信息
14.10 总结
第15章 泛型
15.1 与C++的比较
15.2 简单泛型
15.2.1 一个元组类库
15.2.2 一个堆栈类
15.2.3 RandomList
15.3 泛型接口
15.4 泛型方法
15.4.1 杠杆利用类型参数推断
15.4.2 可变参数与泛型方法
15.4.3 用于Generator的泛型方法
15.4.4 一个通用的Generator
15.4.5 简化元组的使用
15.4.6 一个Set实用工具
15.5 匿名内部类
15.6 构建复杂模型
15.7 擦除的神秘之处
15.7.1 C++的方式
15.7.2 迁移兼容性
15.7.3 擦除的问题
15.7.4 边界处的动作
15.8 擦除的补偿
15.8.1 创建类型实例
15.8.2 泛型数组
15.9 边界
15.10 通配符
15.10.1 编译器有多聪明
15.10.2 逆变
15.10.3 无界通配符
15.10.4 捕获转换
15.11 问题
15.11.1 任何基本类型都不能作为类型
参数
15.11.2 实现参数化接口
15.11.3 转型和警告
15.11.4 重载
15.11.5 基类劫持了接口
15.12 自限定的类型
15.12.1 古怪的循环泛型
15.12.2 自限定
15.12.3 参数协变
15.13 动态类型安全
15.14 异常
15.15 混型
15.15.1 C++中的混型
15.15.2 与接口混合
15.15.3 使用装饰器模式
15.15.4 与动态代理混合
15.16 潜在类型机制
15.17 对缺乏潜在类型机制的补偿
15.17.1 反射
15.17.2 将一个方法应用于序列
15.17.3 当你并未碰巧拥有正确的接口时
15.17.4 用适配器仿真潜在类型机制
15.18 将函数对象用作策略
15.19 总结:转型真的如此之糟吗?
15.19.1 进阶读物
第16章 数组
16.1 数组为什么特殊
16.2 数组是第一级对象
16.3 返回一个数组
16.4 多维数组
16.5 数组与泛型
16.6 创建测试数据
16.6.1 Arrays.fill()
16.6.2 数据生成器
16.6.3 从Generator中创建数组
16.7 Arrays实用功能
16.7.1 复制数组
16.7.2 数组的比较
16.7.3 数组元素的比较
16.7.4 数组排序
16.7.5 在已排序的数组中查找
16.8 总结
第17章 容器深入研究
17.1 完整的容器分类法
17.2 填充容器
17.2.1 一种Generator解决方案
17.2.2 Map生成器
17.2.3 使用Abstract类
17.3 Collection的功能方法
17.4 可选操作
17.4.1 未获支持的操作
17.5 List的功能方法
17.6 Set和存储顺序
17.6.1 SortedSet
17.7 队列
17.7.1 优先级队列
17.7.2 双向队列
17.8 理解Map
17.8.1 性能
17.8.2 SortedMap
17.8.3 LinkedHashMap
17.9 散列与散列码
17.9.1 理解hashCode()
17.9.2 为速度而散列
17.9.3 覆盖hashCode()
17.10 选择接口的不同实现
17.10.1 性能测试框架
17.10.2 对List的选择
17.10.3 微基准测试的危险
17.10.4 对Set的选择
17.10.5 对Map的选择
17.11 实用方法
17.11.1 List的排序和查询
17.11.2 设定Collection或Map为不可
修改
17.11.3 Collection或Map的同步控制
17.12 持有引用
17.12.1 WeakHashMap
17.13 Java 1.0/1.1 的容器
17.13.1 Vector 和 Enumeration
17.13.2 Hashtable
17.13.3 Stack
17.13.4 BitSet
17.14 总结
第18章 Java I/O系统
18.1 File类
18.1.1 目录列表器
18.1.2 目录实用工具
18.1.3 目录的检查及创建
18.2 输入和输出
18.2.1 InputStream类型
18.2.2 OutputStream类型
18.3 添加属性和有用的接口
18.3.1 通过FilterInputStream从InputStream
读取数据
18.3.2 通过FilterOutPutStream向Output-
Stream写入
18.4 Reader和Writer
18.4.1 数据的来源和去处
18.4.2 更改流的行为
18.4.3 未发生变化的类
18.5 自我独立的类:RandomAccessFile
18.6 I/O流的典型使用方式
18.6.1 缓冲输入文件
18.6.2 从内存输入
18.6.3 格式化的内存输入
18.6.4 基本的文件输出
18.6.5 存储和恢复数据
18.6.6 读写随机访问文件
18.6.7 管道流
18.7 文件读写的实用工具
18.7.1 读取二进制文件
18.8 标准I/O
18.8.1 从标准输入中读取
18.8.2 将System.out转换成PrintWriter
18.8.3 标准I/O重定向
18.9 进程控制
18.10 新I/O
18.10.1 转换数据
18.10.2 获取基本类型
18.10.3 视图缓冲器
18.10.4 用缓冲器操纵数据
18.10.5 缓冲器的细节
18.10.6 内存映射文件
18.10.7 文件加锁
18.11 压缩
18.11.1 用GZIP进行简单压缩
18.11.2 用Zip进行多文件保存
18.11.3 Java档案文件
18.12 对象序列化
18.12.1 寻找类
18.12.2 序列化的控制
18.12.3 使用“持久性”
18.13 XML
18.14 Preferences
18.15 总结
第19章 枚举类型
19.1 基本enum特性
19.1.1 将静态导入用于enum
19.2 向enum中添加新方法
19.2.1 覆盖enum的方法
19.3 switch语句中的enum
19.4 values()的神秘之处
19.5 实现,而非继承
19.6 随机选取
19.7 使用接口组织枚举
19.8 使用EnumSet替代标志
19.9 使用EnumMap
19.10 常量相关的方法
19.10.1 使用enum的职责链
19.10.2 使用enum的状态机
19.11 多路分发
19.11.1 使用enum分发
19.11.2 使用常量相关的方法
19.11.3 使用EnumMap分发
19.11.4 使用二维数组
19.12 总结
第20章 注解
20.1 基本语法
20.1.1 定义注解
20.1.2 元注解
20.2 编写注解处理器
20.2.1 注解元素
20.2.2 默认值限制
20.2.3 生成外部文件
20.2.4 注解不支持继承
20.2.5 实现处理器
20.3 使用apt处理注解
20.4 将观察者模式用于apt
20.5 基于注解的单元测试
20.5.1 将@Unit用于泛型
20.5.2 不需要任何“套件”
20.5.3 实现@Unit
20.5.4 移除测试代码
20.6 总结
第21章 并发
21.1 并发的多面性
21.1.1 更快的执行
21.1.2 改进代码设计
21.2 基本的线程机制
21.2.1 定义任务
21.2.2 Thread类
21.2.3 使用Executor
21.2.4 从任务中产生返回值
21.2.5 休眠
21.2.6 优先级
21.2.7 让步
21.2.8 后台线程
21.2.9 编码的变体
21.2.10 术语
21.2.11 加入一个线程
21.2.12 创建有响应的用户界面
21.2.13 线程组
21.2.14 捕获异常
21.3 共享受限资源
21.3.1 不正确地访问资源
21.3.2 解决共享资源竞争
21.3.3 原子性与易变性
21.3.4 原子类
21.3.5 临界区
21.3.6 在其他对象上同步
21.3.7 线程本地存储
21.4 终结任务
21.4.1 装饰性花园
21.4.2 在阻塞时终结
21.4.3 中断
21.4.4 检查中断
21.5 线程之间的协作
21.5.1 wait()与notifyAll()
21.5.2 notify()与notifyAll()
21.5.3 生产者与消费者
21.5.4 生产者-消费者与队列
21.5.5 任务间使用管道进行输入/输出
21.6 死锁
21.7 新类库中的构件
21.7.1 CountDownLatch
21.7.2 CyclicBarrier
21.7.3 DelayQueue
21.7.4 PriorityBlockingQueue
21.7.5 使用ScheduledExecutor的温室控
制器
21.7.6 Semaphore
21.7.7 Exchanger
21.8 仿真
21.8.1 银行出纳员仿真
21.8.2 饭店仿真
21.8.3 分发工作
21.9 性能调优
21.9.1 比较各类互斥技术
21.9.2 免锁容器
21.9.3 乐观加锁
21.9.4 ReadWriteLock
21.10 活动对象
21.11 总结
21.12 进阶读物
第22章 图形化用户界面
22.1 applet
22.2 Swing基础
22.2.1 一个显示框架
22.3 创建按钮
22.4 捕获事件
22.5 文本区域
22.6 控制布局
22.6.1 BorderLayout
22.6.2 FlowLayout
22.6.3 GridLayout
22.6.4 GridBagLayout
22.6.5 绝对定位
22.6.6 BoxLayout
22.6.7 最好的方式是什么
22.7 Swing事件模型
22.7.1 事件与监听器的类型
22.7.2 跟踪多个事件
22.8 Swing组件一览
22.8.1 按钮
22.8.2 图标
22.8.3 工具提示
22.8.4 文本域
22.8.5 边框
22.8.6 一个迷你编辑器
22.8.7 复选框
22.8.8 单选按钮
22.8.9 组合框
22.8.10 列表框
22.8.11 页签面板
22.8.12 消息框
22.8.13 菜单
22.8.14 弹出式菜单
22.8.15 绘图
22.8.16 对话框
22.8.17 文件对话框
22.8.18 Swing组件上的HTML
22.8.19 滑块与进度条
22.8.20 选择外观
22.8.21 树、表格和剪贴板
22.9 JNLP与Java Web Start
22.10 Swing与并发
22.10.1 长期运行的任务
22.10.2 可视化线程机制
22.11 可视化编程与JavaBean
22.11.1 JavaBean是什么
22.11.2 使用Introspector抽取出BeanInfo
22.11.3 一个更复杂的Bean
22.11.4 JavaBean与同步
22.11.5 把Bean打包
22.11.6 对Bean更高级的支持
22.11.7 有关Bean的其他读物
22.12 Swing的可替代选择
22.13 用Flex构建Flash Web客户端
22.13.1 Hello, Flex
22.13.2 编译MXML
22.13.3 MXML与ActionScript
22.13.4 容器与控制
22.13.5 效果与样式
22.13.6 事件
22.13.7 连接到Java
22.13.8 数据模型与数据绑定
22.13.9 构建和部署
22.14 创建SWT应用
22.14.1 安装SWT
22.14.2 Hello, SWT
22.14.3 根除冗余代码
22.14.4 菜单
22.14.5 页签面板、按钮和事件
22.14.6 图形
22.14.7 SWT中的并发
22.14.8 SWT还是Swing
22.15 总结
22.15.1 资源
附录A 补充材料
附录B 资源
索引
《自己动手写JAVA虚拟机》:
前言
第1章 命令行工具
1.1 准备工作
1.1.1 安装JDK
1.1.2 安装Go
1.1.3 创建目录结构
1.2 java命令
1.3 编写命令行工具
1.4 测试本章代码
1.5 本章小结
第2章 搜索class文件
2.1 类路径
2.2 准备工作
2.3 实现类路径
2.3.1 Entry接口
2.3.2 DirEntry
2.3.3 ZipEntry
2.3.4 CompositeEntry
2.3.5 WildcardEntry
2.3.6 Classpath
2.4 测试本章代码
2.5 本章小结
第3章 解析class文件
3.1 class文件
3.2 解析class文件
3.2.1 读取数据
3.2.2 整体结构
3.2.3 魔数
3.2.4 版本号
3.2.5 类访问标志
3.2.6 类和超类索引
3.2.7 接口索引表
3.2.8 字段和方法表
3.3 解析常量池
3.3.1 ConstantPool结构体
3.3.2 ConstantInfo接口
3.3.3 CONSTANT_Integer_info
3.3.4 CONSTANT_Float_info
3.3.5 CONSTANT_Long_info
3.3.6 CONSTANT_Double_info
3.3.7 CONSTANT_Utf8_info
3.3.8 CONSTANT_String_info
……
第4章 运行时数据区
第5章 指令集和解释器
第6章 类和对象
第7章 方法调用和返回
第8章 数组和字符串
第9章 本地方法调用
第10章 异常处理
第11章 结束
附录 指令表
前言/序言
时隔两年多,《Java编程思想(第4版)》的中文版又要和广大Java程序员和爱好者们见面了。这是Java语言本身不断发展和完善的必然要求,也是本书作者BruceEckel孜孜不倦的创作激情和灵感所结出的硕果。《Java编程思想(第4版)》以Java最新的版本JDK5.0为基础,在第3版的基础上,添加了最新的语言特性,并且对第3版的结构进行了调整,使得所有章节的安排更加遵照循序渐进的特点,同时每一章的内容在分量上也都更加均衡,这使读者能够更加容易地阅读本书并充分了解每章所讲述的内容。在这里我们再次向BruceEckel致敬,他不但向我们展示了什么样的书籍才是经典书籍,而且还展示了经典书籍怎样才能精益求精,长盛不衰。
Java已经成为了编程语言的骄子。我们可以看到,越来越多的大学在教授数据结构、程序设计和算法分析等课程时,选择以Java语言为载体。这说明Java语言已经是人们构建软件系统时主要使用的一种编程语言。但是,掌握好Java语言并不是一件可以轻松完成的任务,如何真正掌握Java语言,从而编写出健壮的、高效的以及灵活的程序是Java程序员们面临的重大挑战。《Java编程思想(第4版)》就是一本能够让Java程序员轻松面对这一挑战,并最终取得胜利的经典书籍。本书深入浅出、循序渐进地把我们领入Java的世界,让我们在不知不觉中就学会了用Java的思想去考虑问题、解决问题。本书不仅适合Java的初学者,更适合干有经验的Java程序员,这正是本书的魅力所在。但是,书中并没有涵盖Java所有的类、接口和方法,因此,如果你希望将它当作Java的字典来使用,那么显然就要失望了。
我们在翻译本书的过程中力求忠于原著,为了保持连贯性,对原书第3版中仍然保持不变的部分,我们对译文除了个别地方之外,也没做修改。对于本书中出现的大量的专业术语尽量遵循标准的译法,并在有可能引起歧义之处注有英文原文,以方便读者对照与理解。
全书由陈昊鹏翻译,郭嘉也参与了部分翻译工作。由于水平有限,书中出现错误与不妥之处在所难免,恳请读者批评指正。
深度探索Java虚拟机:从原理到实战的高阶指南 前言 在浩瀚的计算机科学领域,Java虚拟机(JVM)无疑是最为关键的存在之一。它不仅是Java语言执行的基石,更是理解Java高性能、跨平台特性的核心。本书旨在引领读者深入JVM的内部世界,从理论到实践,一步步揭开虚拟机运作的神秘面纱。我们相信,唯有深刻理解JVM,才能真正掌握Java的精髓,编写出更高效、更健壮的代码,甚至在特定领域进行创新性的开发。 第一册:JVM核心原理剖析 第一章:Java虚拟机概览与架构 1.1 虚拟机的重要性与历史演进: 探讨虚拟机的概念,以及JVM在Java生态系统中的核心地位。回顾JVM的发展历程,从JDK 1.0到最新的JDK版本,了解其在性能优化、垃圾回收、并发处理等方面的演进。 1.2 JVM的逻辑架构: 详细解析JVM的整体架构,包括类文件(.class)的加载、验证、准备、解析和初始化过程。介绍JVM运行时数据区,包括程序计数器、Java堆、方法区(元空间)、栈(Java虚拟机栈、本地方法栈)以及它们各自的功能与生命周期。 1.3 字节码:JVM的中间语言: 深入理解Java源代码如何被编译成字节码(Bytecode),以及字节码的特性和优势。通过实例展示常见的字节码指令,为后续的深入分析打下基础。 1.4 JVM与操作系统的交互: 阐述JVM如何与底层操作系统进行交互,包括内存管理、线程调度、I/O操作等。理解JVM如何屏蔽底层硬件和操作系统的差异,实现Java的跨平台性。 第二章:类加载机制详解 2.1 类加载器的概念与作用: 详细介绍JVM提供的三种内置类加载器:根类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和应用程序类加载器(Application ClassLoader)。解释它们之间的父子关系和委派机制。 2.2 双亲委派模型: 深入理解双亲委派模型的工作原理,分析其优势,如保证类的唯一性、防止恶意代码篡改等。通过源码分析和调试,加深对该模型的理解。 2.3 自定义类加载器: 讲解如何编写自定义类加载器,以及在何种场景下需要使用自定义类加载器(如热部署、加密class文件等)。通过实际案例演示自定义类加载器的实现。 2.4 类加载过程:加载、链接(验证、准备、解析)、初始化: 分步详解类加载的三个重要阶段。重点关注链接阶段的验证(保证class文件的安全性)、准备(为静态变量分配内存并初始化为默认值)和解析(将符号引用转换为直接引用)。深入分析初始化阶段的执行顺序和触发时机。 第三章:JVM内存模型与垃圾回收(一):内存区域划分与对象分配 3.1 Java堆:对象的家园: 详细分析Java堆的组成部分:新生代(Eden区、From Survivor区、To Survivor区)和老年代。讲解对象的分配过程,包括在Eden区的创建、Minor GC、对象的晋升机制。 3.2 对象分配原则: 深入理解各种对象分配原则,如大对象直接进入老年代、长期存活对象进入老年代、TLAB(Thread Local Allocation Buffer)的使用等。 3.3 方法区(元空间): 讲解方法区的演变,从永久代到元空间的迁移。分析方法区存储的信息,如类信息、常量池、字段和方法数据、方法体的字节码等。 3.4 栈:局部变量与方法调用的舞台: 详细分析Java虚拟机栈(Java Stack)和本地方法栈(Native Method Stack),包括栈帧(Stack Frame)的结构(局部变量表、操作数栈、动态链接、方法出口等)以及方法调用和返回的过程。 3.5 程序计数器:线程的指挥棒: 讲解程序计数器的作用,用于指示当前线程执行的字节码指令地址。 第四章:JVM内存模型与垃圾回收(二):垃圾回收算法与垃圾收集器 4.1 垃圾回收(GC)的基本概念: 讲解GC的必要性,以及GC的两个核心问题:判断对象是否存活、如何回收对象。 4.2 垃圾回收算法: 详细介绍多种经典的GC算法: 标记-清除(Mark-Sweep): 原理、优缺点(产生内存碎片)。 标记-整理(Mark-Compact): 改进标记-清除,解决碎片问题。 复制(Copying): 原理、适用于新生代,优点(无碎片),缺点(浪费空间)。 分代收集理论: 解释为何采用分代收集,以及各代(新生代、老年代)的特点和适用的GC算法。 4.3 常见的垃圾收集器: 深入分析JVM中各种经典的垃圾收集器,包括它们的特点、适用场景、工作原理及性能指标: Serial GC: 简单、单线程,适用于客户端和单核CPU。 ParNew GC: Serial GC的多线程版本。 Parallel Scavenge GC: 关注吞吐量,适用于需要高吞吐量的场景。 CMS GC(Concurrent Mark Sweep): 关注延迟,适用于需要低延迟的Web应用。 G1 GC(Garbage-First): 区域化并行、并发,适用于大内存、多核CPU,是目前主流的收集器。 ZGC & Shenandoah GC: 关注极低延迟(亚毫秒级),适用于对延迟极其敏感的应用。 4.4 GC日志分析: 学习如何通过GC日志来监控JVM的内存使用情况、GC的频率和耗时,以及如何根据GC日志诊断性能问题。 第五章:JVM性能调优与监控 5.1 性能调优的目标与原则: 明确JVM性能调优的目标(提升吞吐量、降低延迟、减少内存占用等)和基本原则。 5.2 常见的性能瓶颈与排查: 分析CPU、内存、I/O等方面的常见性能瓶颈,以及如何使用工具进行排查。 5.3 JVM参数调优: 详解JVM常用调优参数,包括内存相关的参数(-Xms, -Xmx, -XX:NewRatio等)、GC相关的参数(-XX:+UseG1GC, -XX:MaxGCPauseMillis等)、线程相关的参数以及其他常用参数。 5.4 性能监控工具: 介绍和使用各种JVM性能监控工具,包括: JDK自带工具: `jps`, `jstat`, `jmap`, `jstack`, `jcmd`等。 第三方工具: VisualVM, JConsole, MAT (Eclipse Memory Analyzer Tool), YourKit, JProfiler等。 5.5 实际案例分析: 通过实际项目中的性能问题,演示如何应用所学知识进行问题诊断和性能优化。 第二册:动手实践与源码探索 第六章:理解字节码与字节码增强 6.1}. Class文件结构剖析: 深入研究.class文件的二进制结构,包括魔数、版本号、常量池、访问标志、字段、方法等。学习使用`javap`命令来反编译class文件。 6.2}. 字节码指令集详解: 详细解读JVM的字节码指令集,理解各种指令的功能,如加载/存储指令、算术指令、对象操作指令、控制转移指令、方法调用指令等。 6.3}. 字节码增强技术(ASM/Byte Buddy): 介绍字节码增强(Bytecode Enhancement)的概念,以及常见的字节码增强框架,如ASM和Byte Buddy。 ASM基础: 学习如何使用ASM API来读取、修改和生成字节码。通过实际示例演示如何修改已有的class文件,例如添加日志打印、修改方法返回值等。 Byte Buddy入门: 介绍Byte Buddy的简洁API,如何更方便地进行字节码生成和增强。 6.4}. 动态代理与字节码增强: 结合动态代理的原理,理解字节码增强在动态代理实现中的应用。 第七章:动手构建简易JVM(模拟核心功能) 7.1}. JVM架构模拟: 设计和实现一个简易的JVM模拟器,涵盖核心的组件,如类加载器、指令解释器、内存区域(简化的堆和栈)。 7.2}. 字节码解释器实现: 实现一个基于栈的字节码解释器,能够解析和执行部分Java字节码指令。 7.3}. 简单的内存管理与垃圾回收模拟: 实现一个最基础的内存分配和回收机制,例如简单的标记-清除算法,用于模拟对象在堆中的创建和释放。 7.4}. 方法调用与栈帧模拟: 实现方法调用和栈帧的管理,模拟Java方法执行的过程。 7.5}. 限制与扩展: 讨论在模拟器中实现更复杂功能的挑战,以及可能的扩展方向(如支持更多指令、更复杂的GC算法等)。 第八章:深入理解Java内存模型(JMM)与并发编程 8.1}. JMM的核心概念: 详细阐述Java内存模型,包括主内存、工作内存、原子性、可见性、有序性。 8.2}. 指令重排: 深入理解JVM和CPU的指令重排机制,以及其可能带来的并发问题。 8.3}. JMM的内存可见性保证: 讲解`volatile`关键字的作用,如何实现内存可见性。 8.4}. Java并发关键字与工具: `synchronized`关键字: 讲解锁的机制,包括对象锁和类锁,以及`synchronized`在不同场景下的应用。 `Lock`接口与`ReentrantLock`: 学习使用更灵活的JUC锁。 `java.util.concurrent`包: 介绍`ExecutorService`、`ThreadPoolExecutor`、`Future`、`Callable`、`Semaphore`、`CountDownLatch`、`CyclicBarrier`等常用的并发工具类。 8.5}. 线程安全问题与解决方案: 分析常见的线程安全问题,如竞态条件、死锁、活锁等,并给出相应的解决方案。 第九章:JVM的即时编译(JIT)与性能优化 9.1}. JIT编译器的作用与原理: 介绍JIT(Just-In-Time)编译器的概念,以及它如何将热点代码(HotSpot Code)从字节码编译成本地机器码,从而提高程序执行效率。 9.2}. C1(Client)和C2(Server)编译器: 详细对比C1和C2编译器的特点、优化级别和适用场景。 9.3}. 热点代码探测: 讲解JVM如何通过采样统计(Sampling)或计数统计(Counting)来识别热点代码。 9.4}. JIT编译器的优化技术: 介绍JIT编译器常用的优化手段,如方法内联(Inlining)、逃逸分析(Escape Analysis)、死代码消除(Dead Code Elimination)等。 9.5}. 了解JVM的执行流程: 结合解释执行和JIT编译,全面理解Java程序的执行流程。 第十章:高级主题与实践 10.1}. JVM垃圾回收调优进阶: 深入分析特定场景下的GC调优策略,如大内存应用的GC调优、高并发请求的GC调优。 10.2}. JVM类加载机制的深入应用: 探讨Java Agent、Java Instrumentation等高级类加载机制的应用,如监控、调试、代码注入等。 10.3}. 剖析JVM内部实现: 引导读者在具备一定基础后,可以进一步阅读JVM的开源实现(如OpenJDK)的源码,加深对JVM内部设计的理解。 10.4}. JVM中的其他高级特性: 简要介绍JVM的一些其他高级特性,如类文件格式的演变、invokedynamic指令、模块化(Project Jigsaw)等。 10.5}. 虚拟机发展趋势与未来展望: 探讨JVM未来的发展方向,如GraalVM、WebAssembly等,以及它们对Java生态的影响。 结语 掌握Java虚拟机,就像获得了一把解锁Java语言强大潜力的金钥匙。本书从理论基础到实践操作,旨在为读者构建一个全面而深入的JVM认知体系。我们鼓励读者在阅读过程中,勤于思考,勇于实践,利用各种工具进行探索和验证。愿本书能成为您在Java虚拟机领域求知路上的有力伙伴,助您成为一名真正精通Java的开发者。