第三章
1. 基本/对象数据类型
(1)基本数据类型:只有值,不可变,廉价,在栈中,使用时存在,无法实现表达的统一
(2)对象数据类型:继承自Object,有不同身份,有些可变,更昂贵,在堆中,等待垃圾回收,表达与泛型统一
2. 静态/动态类型检查
(1)静态检查:代码运行之前,检查名称、语法、参数数量和类型、返回类型,优于动态检查
(2)动态检查:代码执行时,检查非法参数值、不可表示的返回类型、数组越界、空指针引用
3. 可变性与不变性
(1)不变性:主要的设计原则
·不变数据类型创建完后,值不可修改(final),指定引用位置后,不可再次指定
·final class不能再被继承,final method不能被重写
·优点:可理解性强、易读、安全、不需要被防御性复制
(2)可变性:可以改变变量值,方便分享、方便作为全局变量
(3)例:String和StringBuilder
String t = s; t = t + “c”; 指向新对象
StringBuilder tb = sb; tb.append(“c”); 改变原来的值
4. 值/引用的改变:改变引用是改变指针,改变值是在这个指针下改变对象内容
5. 防御式复制:针对可变对象而言,返回一个复制的新对象,占用额外空间
6. 快照图
(1)原始值快照图示例:
(2)对象快照图示例:
7. 规格说明、前置/后置条件
(1)规格说明:名称、功能、参数、返回值
(2)前置条件(requires)是客户的任务,后置条件(effects)是实现者的义务,前置条件满足时,应满足后置条件,前置条件未满足时,后置条件无所谓。
(3)JavaDoc:
8. 行为等价性:用一个实现代替另一个实现。为了使替代成为可能,需要一个规范来说明客户端依赖的内容,规范不应提及方法类的局部变量或私有字段。
9. 规约的强度:若S2强于S1,要么前置条件弱,要么后置条件强
10. ADT操作的四种类型
(1)Creator:创建该类型的新对象,可作为构造函数来实现,静态实现的通常称为工厂方法
(2)Producer:从该类型的旧对象创建新对象
(3)Observer:获取抽象类型对象并返回不同类型的对象
(4)Mutator:改变对象,通常为void,此时必须被调用,有时返回boolean
11. 表示独立性:数据类型与实现它的数据结构或数据字段独立,如List的操作与它是Array还是Linked无关,仅依赖于公共方法的规范。
12. 表示泄露:ADT的实现可见、可被客户端修改。
13. 不变量、表示不变量RI
(1)不变量:程序的属性,每个抽象数据类型都应保有自己的不变量,这些不变量被构造函数创建后保持不变,其正确性不依赖于其他模块,由公共方法调用维护,方法执行期间可能暂时失效。
(2)表示不变量RI:RI将表示值映射为Boolean,当该值能被映射到AF中时为真。
14. 表示空间、抽象空间、AF
(1)表示空间(R):由实际的值组成
(2)抽象空间(A):由该类型支持的值组成
(3)AF:R -> A的映射关系(满射、未必单射)
15. 以注释的形式撰写AF 、RI
(1)例子:
(2)注意
·对于相同的表示空间和相同的表示不变式也可以用不同的RI和AF描述
·不能用RI决定AF
·可用范围对表示集合
16. 接口、抽象类、具体类
(1)对象:拥有状态(字段)和行为(方法)
(2)接口:一种用于设计和表达ADT的语言机制,方法的列表
·一个接口可以扩展其他接口
·一个类可以实现多个接口,一个接口也可以有多个实现
·接口中不能包含构造函数,必须调用实现类的构造函数
·优点:
- 客户端只需通过接口了解方法
- 抽象数据类型的多个不同表示可以作为实现接口的不同类共存于同一个程序中
- 通过对多个实现在性能和bug free方面的比较,进行实现的选择
(3)抽象类:至少包含一个抽象方法的类
(4)具体类:不包含抽象方法的类
17. 继承、重写
(1)继承(extends):用于代码重用,超类的方法在子类中隐式可用
(2)子类型(implements):用于多态,子类可代替超类
(3)重写:为超类或父类中已经提供的方法提供具体实施
·与超类或父类拥有相同的名称、参数和返回值
·方法的版本将有调用它的对象决定
·若父类调用,执行父类方法,若接口类调用,执行子类方法
·严格继承的子类只能添加新方法,不能重写原来的方法
·子类中可以通过super调用父类中被重写的方法
18. 多态、重载
(1)多态
·一个函数可以有多个同名的实现
·一个类型名字可以代替多个类型:即泛型,客户端可以对不同类型的对象使用统一的方式进行处理
·一个变量名字可以代表多个类的实例:如ArrayList与LinkedList都是List的子类型
- instanceof:用来在运行时指出对象是否是特定类的一个实例,用法为result = object instanceof class,返回Boolean
(2)重载:保有相同方法名,可以有不同参数,方法的重载可以在此类也可以在子类
·例子:
·重载与重写的区别
| 重载 | 重写 |
参数列表 | 必须更改 | 不能更改 |
返回类型 | 可以更改 | 不能更改 |
异常 | 可以更改 | 可以减少或消除,但不得抛出新的或更广泛的检查异常 |
访问 | 可以更改 | 不能做更多的限制,但可以减少 |
调用 | 引用类型决定选择哪个重载版本。被调用的实际方法仍然是在运行时发生的虚拟方法调用,但编译器将始终知道要调用的方法的签名,所以在运行时,参数匹配已经被确定下来,而不是该方法所在的实际类 | 对象类型(堆上实际实例的类型)决定选择哪种方法在运行时发生 |
19. 泛型
·数据类型和函数根据待指定的类型编写,在需要时作为参数提供的特定类型实例化
·四种使用方式:泛型类声明、泛型接口声明、泛型方法声明、泛型构造函数
·泛型类:声明了一个或多个类型变量的类,类型变量用<>括起
·通配符:通常用 * 或 ? 表示,如List<?> 或 List<? extends Animal>
- ArrayList<String> 是List<String> 的子类型
- List<String> 不是List<Object> 的子类型
- List<String> 是List<? extends Object> 的子类型
- List<Object> 是List<? super String> 的子类型
20. 等价性equals和==
(1)==:比较引用,若指向内存中的相同存储则相等,原始数据类型必须使用==
(2)equals:比较对象内容,必须为每个抽象数据类型适当地定义该操作
·例子:
·性质:自反、对称、传递、不等于null
21. hashCode()
(1)使key均匀分布在索引上,但偶尔会发生冲突
(2)插入时,将键值对添加到由hash code确定的阵列插槽的列表中
(3)如果两个对象根据equals方法相等,则对这两个对象中的每个对象调用hashCode方法必须产生相同的整数结果
(4)如果重写了equals方法,必须重写hashCode方法
(5)除非对象改变,hashCode值不应改变
22. 可变对象的观察等价性、行为等价性
(1)观察等价性:两个引用不能通过不改变任何一个对象的状态的代码来区别,即通过只调用observer,producer和creator方法,客户端可调用similar来获取一个观察等价的对象。
(2)行为等价性:两个引用不能通过任何代码加以区分,即使在一个代码上调用了mutator,而另一个代码则不会调用它,equals通常实现行为等价。
(3)对于不可变对象,观察和行为平等是相同的,因为没有任何增变方法。