目录

1 第1章 初识Java

Tip

本章介绍了Java的历史,不是说“历史是一面镜子”么?

1.1 JAVA简介

1.1.1 Java初次登场 
1.1.2 指导Java发展的两份文档 
1.1.3 Java面对的问题以及解决方案

1.2 JAVA语言进化史

1.3 小朋友,你是不是有很多问号?

1.3.1 为什么James Gosling被称为终身仁慈独裁者? 
1.3.2 Java的名字是谁起的? 
1.3.3 James Gosling如何回答相比于C语言,Java不够自由? 
1.3.4 Java的现状怎么样?

1.4 程序员故事

2 第2章 第一行代码

Tip

这一章的内容主要是把开发环境配置起来,运行第一个程序,在屏幕上输出两个单词:Hello World。

2.1 “传统”JAVA版的Hello World

2.1.1 用什么工具来输入代码?
2.1.2 输入的时候需要注意什么?
2.1.3 如何让源代码跑起来?
2.1.4 碰到bug怎么办?

2.2 八仙过海的Java虚拟机

2.2.1 Sun的虚拟机
2.2.2 BEA的JRockit
2.2.3 微软的JVM
2.2.4 Apache的Harmony
2.2.5 Google的Dalvik
2.2.6 我的感慨

2.3 “脱口秀”之表扬与自我表扬

2.4 小朋友,你是不是有很多问号?

2.4.1 bytecode是什么?
2.4.2 javac是编译器么?
2.4.3 Java虚拟机只能运行Java语言么?

2.5 “未来版”的Hello World

2.5 《万物皆零一》

3 第3章 面向对象编程

Tip

这一章讲了面向对象编程的历史,并考证了面向对象编程这几大知识点的由来以及用途。

3.1 第一门面向对象编程语言——Simula

3.1 面向对象发明者的故事
3.2 Simula的研究成果
3.3 推广Simula

3.2 Java中的一切皆对象

3.2.1 什么是对象
3.2.2 对象怎么工作

3.3 面向对象为什么这么难?

3.3.1 名词搅拌器
3.3.2 滥用隐喻
3.3.3 过度宣传

3.4 面向对象可以很简单

3.4.1 FIFA足球游戏
3.4.2 对球员进行抽象
3.4.3 继承

3.5 虚构的访谈

3.6 《万物皆零一》

4 第4章 变量

变量是构建程序最基本的单位,本章从变量的历史讲起,涵盖了变量命名、变量类型、变量作用域等内容。

4.1 变量的历史

4.2 变量的命名

4.3 变量的数据类型

4.3.1 基本数据类型
    4.3.1.1 整数类型
    4.3.1.2 浮点数类型
      《考据癖:计算机处理小数的历史》
    4.3.1.3 字符类型
      《考据癖:计算机处理字符的历史》
    4.3.1.4 布尔类型
    4.3.1.5 类型转换
4.3.2 引用数据类型

4.4 变量的作用域

4.4.1 Java变量的作用域
4.4.2 作用域的历史
4.4.3 虚构的故事:动态作用域与静态作用域

5 第5章 操作符

小学时候就学了算数操作符与赋值操作符,可能逻辑操作符有一点难度,至于自增、自减那些,一语也就点破了,总之,本章实在是没难度。

5.1 算数操作符

5.2 赋值操作符

5.3 关系操作符

5.4 逻辑操作符

5.4.1 逻辑与(AND)
5.4.2 逻辑或(OR)
5.4.3 逻辑非(NOT)

5.5 自增、自减操作符

5.6 位操作符

5.7 三元操作符

5.8 操作符的优先级

6 第6章 结构化编程

人类开发软件之后,遇到了第一次软件危机,经过众多科学家的折腾,终于捯饬出来了结构化编程……简单来说,所有的编程都可以用顺序、选择与循环来搞定,我给出了他们当初的论文来证明这一点。这一章算是非常重要的。

6.1 结构化编程的由来

6.2 顺序结构

6.2.1 前后顺序无关的代码
6.2.2 有明确顺序的代码

6.3 选择结构

6.3.1 if语句
6.3.2 switch语句

6.4 循环结构

6.4.1 do-while循环
6.4.2 while循环
6.4.3 for循环
6.4.4 增强的for循环
6.4.5 break与continue
6.4.6 标签

7 第7章 方法

英国科学家大卫·惠勒(David Wheeler)发明了方法,从此所有的编程语言都开始支持方法。可以说,没有方法,无法进行编程。同时,递归是一种比较特殊的方法,如果运用恰当,可以大大简化编程。

7.1 方法的概述

7.2 方法的声明与调用

7.3 方法的参数

7.3.1 命名参数
7.3.2 可变参数
7.3.3 形参与实参

7.4 方法的返回值

7.5 递归

7.5.1 递归步骤与终止条件
7.5.2 递归实现科赫雪花

8 第8章 数组

Warning

数组是一种古老的数据结构,太过于“原始”,我觉得应该使用更先进的ArrayList等数据结构。但是,数组仍有大量的人在使用,所以,我们也要学习。

8.1 数组概述

8.2 数组的声明

8.3 数组的初始化

8.3.1 静态初始化
8.3.2 动态初始化

8.4 多维数组

8.4.1 二维数组
8.4.2 三维数组

8.5 用数组实现本福特定律

9 第9章 类、对象与封装

如何把功能相关的代码组织到一起呢?答案是用“类”。

9.1 类、对象与封装

9.2 属性与方法

9.2.1 访问修饰符
9.2.2 getter和setter方法
9.2.3 构造函数
9.2.4 如何使用this关键字?

9.3 静态成员

10 第10章 包

如何把功能相关的类组织到一起呢?答案是用“包”。

10.1 包的简介

10.2 包的语法与用法

10.2.1 如何声明包
10.2.2 如何导入包
10.2.3 如何使用包中的成员

10.3 使用包的最佳实践

10.3.1 如何命名包?
10.3.2 如何以包为结构组织项目代码

11 第11章 继承

权力可以继承,财富可以继承,代码就不可以继承么?当然能!

继承最重要的功能是为了代码重用,减少代码的重复。官/富二代最重要的功能也是继承富一代的权与钱,减少从零奋斗的过程。

11.1 什么是继承

11.2 类实例的继承机制

11.2.1 子类可以继承父类的属性么?
11.2.2 子类可以继承父类的方法么?
10.2.3 如何使用super关键字?

11.3 静态成员的继承机制

11.4 不可被继承的类和方法

11.4.1 final用于修饰类是用来阻止类被继承
11.4.2 final用于修饰方法是阻止方法被覆盖

11.5 多重继承的问题

12 第12章 抽象类

在《公孙龙子·白马论》中提出了“白马非马”的诡辩,如果第二个马是抽象类的话,那么“白马”就是“马”。“公孙龙”认为“马”不能实例化,但是“白马”可以实例化。

我认为战国时期的公孙龙所持有的“每个事物只能是它自己,事物间不存在联系”的观点是错误的,至少在面向对象中是如此。

不能实例化的“马”,在面向对象编程中叫“抽象类”。

12.1 抽象类概述

12.2 抽象类的实现

13 第13章 接口

在11章里讲过,Java不能多重继承,爸当官,妈当官,难道孩子不能同时继承两者的权力与财富么?在现实中,肯定能!(不信你看哪个公子,哪条鲶鱼,都是多重继承的……)

但是在Java中却不能,Java不支持多重继承,如果你需要多重继承怎么办?用接口。

http://www.gotw.ca/publications/c_family_interview.htm 在这篇访谈中,C++的作者与Java的作者,都谈到了编程语言的设计,其实Java的作者对接口与类的设计也不满意。

13.1 接口的历史

13.2 接口的定义与实现

13.3 接口与抽象类

13.4 接口引入DEFAULT方法

13.5 接口中引入静态方法

13.6 接口的继承与多重继承

13.6.1 接口的作用
13.6.2 接口与抽象的区别

14 第14章 多态

什么动物婴儿时四条腿,成年后两条腿,老年时三条腿?答案是:人。

当我们调用走路的时候,同样的人,但是有不同的走路形态,小时候爬,长大后两条腿,老年后拄着一根拐杖。

这就是多态,用统一的方式(走路),却实现了不同的形态(爬,走,拄拐)。

本章介绍了如何用不同的方法实现多态。

14.1 用继承来实现多态

14.1.1 方法重写(Override)为多态提供基础
14.1.2 向上转型(Upcasting)为多态提供统一调用方式

14.2 用接口来实现多态

14.3 用继承与用接口实现多态有什么不同?

14.4 用泛型来实现多态

15 第15章 集合

第8章的时候,我“黑”了一下数组,数组作为一种数据结构,实在是太原始了。

那用什么方法来代替数组呢?就是本章讲的集合。

集合比数组好用太多了,不一个时代的产品。

15.1 集合的基本概念

15.1.1 什么是集合
15.1.2 集合与数组的区别

15.2 Java集合框架的架构体系

15.3 集合的核心接口与实现类

15.3.1 Iterable接口
15.3.2 Collection接口
15.3.3 List接口以及实现类
15.3.4 Set接口以及实现类
15.3.5 Map接口以及实现类

16 第16章 异常处理

嫦娥应悔偷灵药,碧海青天夜夜心。

嫦娥犯的错,只能无限的懊悔,毕竟没有后悔药卖。但是Java中,为异常处理设置了非常多的防御措施,确保嫦娥偷不到灵药,防患于未然 :)

16.1 异常的基础概念

16.1.1 什么是异常
16.1.2 异常的类型和层次结构
16.1.3 Error和Exception的区别

16.2 异常捕获处理

16.2.1 throws语句
16.2.2 try-catch-finally语句

16.3 Java内置的常见异常类型

16.3.1 非受检异常(Unchecked Exception)
16.3.2 受检异常(Checked Exceptions)
16.3.3 错误(Error)

16.4 自定义异常

16.5 异常链

16.6 异常与资源管理

17 第17章 函数式编程

绝大部分Java编程书上,都不讲泛型,一是太难,二是觉得没什么用。但是,看看下面的语言:

Java之前不支持泛型,Java 5之后增加了泛型。
C#之前不支持泛型,C# 2.0之后增加了泛型。
Go语言之前不支持泛型,Go1.18之后增加了泛型。

难肯定是难的,有用肯定是有用的,花点时间是值得的。

泛型解决的问题与继承、多态解决的问题是一脉相承的:代码复用。比如容器中可以存整数,也可存小数,还可以存小猫小狗这样的对象……如果逻辑一样,一点小改动就要重新调整代码,自己也受不了……

现实中也是如此,油罐车可以拉煤油,可以拉汽油,甚至可以拉食用油……这当然可能会出现各种安全问题,所以需要很多的技术来确保安全。

17.1 泛型的概念与作用

17.1.1 Java泛型的历史
17.1.2 泛型的用途与语法

17.2 如何定义泛型类?

17.3 如何定义泛型接口?

17.4 如何定义泛型方法?

17.4.1 泛型方法和多态的区别
17.4.2 泛型方法与泛型类、泛型接口的区别

17.5 类型通配符的概念与使用场景

17.5.1 无界通配符(?)的概念与使用场景
17.5.2 上界通配符(\<? extends XXX\>)的概念与使用场景
17.5.3 下界通配符(\<? super XXX\>)的概念与使用场景
17.5.4 通配符的PECS(Producer Extends,Consumer Super)原则

17.6 泛型的继承与子类型规则

17.6.1 泛型的不变性规则及其影响
17.6.2 通配符的协变规则与逆变规则

17.7 泛型中的类型擦除

17.7.1 什么是类型擦除
17.7.2 JVM在编译时如何处理泛型
17.7.3 类型擦除对编程的影响
17.7.4 泛型对数组的影响

18 第18章 函数式编程

离婚的原因是什么?千千万万,但是最重要的一个是:心变了。

bug的原因是什么?千千万万,但是最重要的一个是:状态变了。

什么叫状态变了呢?64核的CPU中,有1个核修改了全局变量,但其它63个核不知道;有个文件被修改了,但其它进程不知道…… 状态改变,是bug的高发原因。

如何让离婚率变为0?方法是减少结婚,有感情的就同居得了。

如何让bug减少?方法是减少命令式编程,增加函数式编程。

于是,随着CPU核心的增多、分布式、协同式程序的增多,不改变程序状态的函数式编程“死灰复燃”了……

本章从Lisp历史谈起,让大家清晰的了解什么叫函数式编程,为何Java的函数式编程不如Lisp那么优雅……

18.1 第一门函数式编程语言:LISP语言

18.1.1 Lisp简介
18.1.2 Racket以及Racket的语法

18.2 Lambda表达式

18.2.1 什么是Lambda表达式
18.2.2 无参数的Lambda表达式
18.2.3 有一个参数的Lambda表达式
18.2.4 有两个参数的Lambda表达式
18.2.5 如何将Lambda表达式赋值给变量?

18.3 函数式接口

18.3.1 为什么需要函数式接口?
18.3.2 函数式接口的种类有多少?
18.3.3 函数式接口为何只能有一个抽象方法?
18.3.4 方法引用
18.3.5 如何自定义函数式接口?

18.4 Stream API

18.4.1 什么是Stream
18.4.2 创建Stream的各种方式
18.4.3 Stream操作的分类
18.4.4 常见的中间操作
18.4.5 常见的终端操作

19 第19章 枚举类型

在Java中,枚举已经强大到什么地步了呢?几乎所有类能做的事情,枚举都能做。枚举是一种特殊的类。

枚举不止是简单的常量的集合,还可以拥有属性、方法和构造函数。还支持接口和实现。

简单来说,枚举是受限的类

19.1 枚举概述

19.1.1 什么是枚举
19.1.2 枚举和常量的区别

19.2 定义枚举

19.3 枚举的高级特性

19.3.1 枚举类型不能继承,但是可以实现接口
19.3.2 枚举无法被实例化
19.3.3 枚举常量实例最好设置为final
19.3.4 不能依赖于枚举常量的序数
19.3.5 values()和valueOf()方法
19.3.6 EnumSet和EnumMap

20 第20章 注解

注解是Java 5之后引入的。

对司机而言,开车的时候,最重要的信息是路上的指示牌。比如看到“前方有急转弯”,你就会注意一点。

同样,注解类似于这些路牌,当看到@Override的时候,编译器会去查一下父类中是否有这个方法,当看到@Deprecated的时候,会提示这个方法已经过时了……

注解的本质是提供额外的元数据和指示,帮助编译器、工具和开发者更好地理解和处理代码。

20.1 什么是注解

20.2 在代码中使用Java预定义的注解

20.2.1 注解与注释的区别
20.2.2 使用Java预定义的注解

20.3 在代码中使用自定义的注解

20.3.1 定义注解
20.3.2 使用注解
20.3.3 解析注解

21 第21章 反射

据说,违反法律最刺激,要是违反了法律还不被制裁,就更是刺激了。比如古人有云:“妻不如…”,这句话你自己去搜搜吧。

前面我们讲类的作用,又是封装,又是隐藏。然后突然来一个机制,啥封装,啥隐藏?直接给你显微镜下看的明明白白的,并且能越过限制调用方法……是不是很刺激?

反射就是这样的,使用反射,咱们可以正大光明的走后门,所有的类定义的条条框框,都可以不用遵守。让你觉得像个特权阶级。

21.1 反射的历史与发展

21.1.1 起初,反射仅仅是为了跨平台
21.1.2 后来,反射的发展就“失控”了

21.2 获取Class对象

22.2.1 Class对象是Java反射机制的基础
22.2.2 获取Class对象的三种方式

21.3 基础的反射API

21.3.1 构造类操作
21.3.2 属性类操作 
21.3.3 方法类操作

21.4 MethodHandler和VarHandle

21.5 反射的局限

21.5.1 性能开销问题
21.5.2 破坏封装性
21.5.3 反射代码往往难以维护
Important

这本书写了21章,而且肯定还有很多内容没有覆盖到,如果我说一些漂亮话,什么“书山有路勤为径,学海无涯苦作舟”,让大家再多学点什么的,一般人实际上内心是比较崩溃的。

那学到什么时候是个头啊?!

实际上,你根本不需要学这么多。我之所以写这么多,是因为这是“写书”,其目的是“尽量覆盖”,而现实中做项目,其目的是“尽快做完下班”。

如果你继续读我剩下的三本书,你会发现,每本书都只是用到这本书里“部分内容”,比如做游戏,你就用不到反射,也用不到函数编程,因此会不会这些稀奇古怪的东西,对开发游戏完全没影响。