第一章 基础
1.1 基础编程模型 4
1.1.1 Java程序的基本结构 4
1.1.2 原始数据类型与表达式 6
1.1.3 语句 8
1.1.4 简便记法 9
1.1.5 数组 10
1.1.6 静态方法 12
1.1.6.4 递归
编写递归代码最重要有以下三点:
- 递归总有一个最简单的情况——方法的第一条语句总是一个包含return 的条件语句。
- 递归调用总是尝试去解决一个规模更小的子问题,这样递归才能收敛到最简单的情况
- 递归调用的父问题 和 尝试解决的 子问题之间 不应该有交集。
1.1.7 API 16
1.1.7.4 你自己编写的库
API的目的是将调用和实现分离:除了API中给出的信息,调用者不需要知道实现的其他细节,而实现也不应考虑特殊的应用场景。
- 程序员可以将API看做调用和实现之间的一份契约,它详细说明了每个方法的作用。实现的目标就是能够遵守这份契约。
1.1.8 字符串 20
1.1.9 输入输出
在我们的模型中,Java程序可以从命令行参数或者一个名为标准输入流的抽象字符流中获得输入,并将输出写入另一个为标准输出流的字符流中。
1.1.9.4 标准输入
标准输入流最重要的特点是这些值会在你的程序读取之后消失。只要程序读取一个值,它就不能回退并再次读取它。
1.1.9.5 重定向与管道
1.1.10 二分查找 28
1.1.11 展望 3
1.1答疑:
- 1 / 0 与 1.0 / 0.0 的结果是什么?
- 1.0 / 0.0 = INFINITY
- 1 / 0编译出错 除零异常 ,
java.lang.ArithmeticException: / by zero
- 一个for循环 和 while形式有什么区别?
- 答:while 循环中的 “递增变量” 在循环结束后还可以继续使用。
习题1.1.25 使用数学归纳法证明欧几里得算法
- 欧几里得算法的关键在于证明 gcd(a, b) = gcd(b,a mod b) 的正确性
定理:a,b 是整数,则gcd(a, b) = gcd(b,a mod b)
设k,r为整数。设r = a mod b ,则a可表示为 a = r + k*b
- 假设d 是{a,b}的公约数,则d整除a,b。而r = a - k*b; 所以d整除r, d也是b和r的公约数。
- 假设d 是{b,r}的公约数,则d整除b,r。而a = r + k*b 所以d也是a,b的公约数。
- 所以{a,b},{b, r}的公因子集合是一样的。特别地{a,b}的最大公因子也是{b,r}的最大公因子。即 gcd(a, b) = gcd(b,a mod b)
1.2 数据抽象
数据类型指的是一组值和一组对这些值的操作的集合。
- Java编程的基础主要是使用class关键字构造被称为 引用类型 的数据类型。
- 抽象数据类型(ADT)是一种能够对使用者隐藏数据表示的数据类型。
1.2.1 使用抽象数据类型
1.2.1.4 对象
- 对象是能够承载数据类型的值的实体。
- 所有对象都有三大特性:
- 状态:即类型中的值(实例变量)
- 标识:能够将一个对象区别于另一个对象。可以认为对象的标识就是它在内存中的位置(每个类都至少有一个构造函数以创建一个对象的标识)
- 行为:数据类型的操作()
- 引用是访问对象的一种方式。
1.2.2 抽象数据类型举例
1.2.3 抽象数据类型的实现
1.2.3.5 API 用例与实现
- 我们思考的不是应该采取什么行动来来达成某个计算性的目的,而是用例的需求。按照下面三步走的方式用抽象数据类型来满足它们。
- 用例一般需要什么操作?
- 数据类型的值应该是什么才能最好地支持这些操作?
- 定义一份API:API的作用是将使用和实现分离,以实现模块化编程。
- 用一个Java类实现API的定义:首先我们选择适当的实例变量,然后再编写构造函数和实例方法。
- 实现多个测试用例来验证前两步做出的设计决定。
1.2.4 更多抽象数据类型的实现
1.2.4.2 维护多个实现
同一份api的不同实现。
通常采用一种非正式的命名约定
- 通过前缀性修饰符区别同一份API的不同实现
- 维护一个没有前缀的参考实现,它应该适合于大多数用例的需求。
1.2.5 数据类型的设计
抽象数据类型是一种向用例隐藏内部表示的数据类型。
我们提倡的编程风格:将大型程序分解为能够独立开发和调试的小型模块(也促进了代码复用)。
Java系统的新实现往往更新了多种数据类型的或静态方法库的实现,但它们的API并没有变化。
1.2.5.8 等价性
equals 模板
@Override
public boolean equals(Object obj) {
//如果引用相同,直接返回true 不需要其他测试工作
if (this == obj) {
return true;
}
//对象为空直接返回false
if (obj == null) {
return false;
}
//两个对象的类不同
if (obj.getClass() != this.getClass()) {
return false;
}
// //书上没这么用,还是直接getClass比较好
// if (!(obj instanceof Date)) {
// return false;
// }
//强制类型
Date that = (Date)obj;
if (that.day != day) {
return false;
}
if (that.year != year) {
return false;
}
if (that.mon != mon) {
return false;
}
return true;
}
1.2.5.10 不可变性
- 不可变数据类型,该类型的对象的值在创建之后就无法再被改变(final修饰)
- eg:String
- 可变数据类型,能够操作并改变对象中的值
- eg:数组
1.2.5.13 断言
契约式设计的编程模型采用的就是断言的思想。
- 数据类型的设计者需要说明前提条件(调用某个方法需要满足的条件,如:二分查找需要满足有序)
- 后置条件(实现在方法返回时必须达到的要求)
- 副作用(方法可能对对象状态产生的任何变更)
答疑:
要保证含有一个可变的实例变量的数据类型的不可变性,需要得到一个本地副本,称为保护性复制。
1.3背包、队列和栈
1.3.1 API
1.3.1.4 背包
背包是一种不支持从中删除的集合数据类型——它的目的是帮助用例收集元素并迭代遍历所有收集到的元素。(当然可以检查背包是否为空或者获取其中的数量的功能还是有的)。
- 进出栈的顺序
- 进栈的顺序的已经定死了
- abc 依次进。—— a进 … b 进 … c 进 …
- 那么区别就只在于进栈之间的出栈元素。
- 如果