第七章:Object-Oriented Programming
1.Some Conception
Object
对象。一个对象是状态与行为的结合。
状态:包括在对象中的数据。Java中即是fields。
行为:由对象提供的动作。Java中的method
Class
类。每个对象所属的类。一个类定义了method和field,同时定义了类型与实现。
Static vs. Instance variables/methos of a Class
- 类成员变量:与类关联而非与类的实例相关联的变量。
- 类方法
- 实例变量
- 实例方法:只能通过实例调用
类成员变量和类方法都是静态(static)的,而实例变量和实例方法都是实例(instance)的。
闲:将一个变量或者方法声明为静态的还是实例的,需要考虑。比如尝试创建一个Dog类,将狗的叫声作为静态变量显然是不合适的。如果想比较两只狗的体重,是应该让每个狗的实例都有与另一只狗比较体重的能力,还是将这个能力赋予Dog类,从而像天平一样为他们称重呢?
Interface
接口,在计算中是计算机系统的两个或多个独立组件交换信息的共享边界。
接口充当一个交互界面,使外部可以访问或者更改它的内部,但是内部发生的变化并不会影响外界与它交互的方式。例如人类与计算机的交互,就是通过各种外部设备如鼠标、键盘、显示屏进行的,而无论人类对计算机的系统进行了何种操作,人类操纵计算机的形式仍然是不变的。
Java中的接口依靠类实现,体现为没有函数体的函数签名列表。
定义ADT的一种方法就是将其声明为接口,而ADT的实现就是接口的实现。
接口的实现:一个类以implements子句声明为某接口的实现,一个类可以同时实现多个接口。
接口的扩展:一个接口可以扩展其他多个接口。
接口能令客户端仅仅接触到规约。接口的内容应该是客户端能知道的全部内容。
Abstract class
抽象类。
抽象方法:只有函数签名而没有函数体的方法。
至少含有一个抽象方法的类是抽象类。
接口时只包括抽象方法的抽象类。通过抽象类,可以部分实现接口,未实现的方法仍保留即可。
2.Subtyping
子类型(子类型多态性subtype polymorphism 、包含多态性inclusion polymorphism)是类型多态的一种形式。子类型在某种程度上可以替代超类型supertype,即一切适用于超类型的操作都可以对子类型生效。
如果S是T的子类型,那么子类型关系:S <: T, S ⊑ T, S ≤: T 意味着S类型的任何部分都可以安全地在T中实现。在Java中体现为,S的规约至少和T的一样强,以满足一切T能满足的需求。
Structral subtyping
结构子类型化:在Java中不支持。
如果S至少提供了T所需要的所有操作——一致的public methods 和 public instance variables,那么S可以被认为是T的子类型,不必声明为T的扩展或实现。
Subclassing
Java中,为一个类创建子类型有两种方法:
- 实现接口
- 子类化:定义一个类的扩展extension或子类subclass
子类化:
- 子类自动继承超类的实例方法,包括它们的方法体
- 子类可以重写/覆盖(override)超类的任何函数体
- 子类也能继承超类的私有字段
- 子类可以添加自己的实例方法和rep
子类化实际上是对于现实更贴切的描绘。例如水果是一个大类,而苹果类可以是水果的扩展,也可以是水果的扩展(添加苹果类独有的特点),不同品种的苹果类又可以进一步扩展苹果类,即进一步添加独有的特点。
3.Overriding and Dynamic Dispatch
Java中每个类的都是Object的子类,并自动继承像toString()这样的方法。为确保类正常工作,经常需要重写所继承的实现。
当一个方法有多个实现时,Java必须决定调用该方法时使用哪种实现——调度方法。
Java使用的是动态调度Dynamic dispatch:
使用与对象的动态类型相匹配的方法实现,而不是指向对象的引用的静态类型实现的方法。
例如在 FastMyString类中重写Object类的toString():

调用代码为:
其结果仍然为:
Hello World
说明:进行静态检查时,fastMyString类型被编译为Object,因此所有Object不具备的操作这个引用都不能执行。但是当程序运行时,通过赋值操作,令fastMyString指向了FastMyString的实例,所调用的toString方法也是FastMyString类的方法。
即,Dynamic dispatch:对象在运行时的类型决定它调用的实现。
动态调度的前提是所调用的子类的方法必须在超类中存在,即要么所调用的方法是超类方法的重写,要么直接调用超类的方法。
4.Generic Types
泛型。
泛型利用一个类型参数,声明在<>之中。
例如:
interface MySet<T>{...}
class InSet implements MySet<T>{..}
class InSet2 implements MySet<Integet>{..} 将类型声明替换为Integet之后,必须将实现中的所有T都替换为Integer。
interface GrowingSet<Z> extends MySet<Z>{..}
将<>中的类型看作一个类或一个接口的局部变量。GrowingSet有自己的类型参数Z。
注意:
- 泛型是类型不可变的。ArrayList<String>是List<String>的子类型,而不是List<Object>的子类型。
- 类型参数<T>的信息在代码编译完成后即被丢弃,在运行期不可用,Java中编译器会把类型参数替换为其上界,如果上界没有定义,则默认为Object。那么,给定两个具体类MyClass<A>和MyClass<B>,它们没有任何关系,即便A是B的子类或者其他。
5.Getter & Setter
一种设计思想。
将实例变量设计为private,并在必要时使用getter和setter方法访问或修改它。
这样可以按照实现者意愿控制用户能获取的信息。
6.Polymorphism
多态。
多态的三种类型:
- 临时多态:一个函数表示不同或潜在的异构实现。利用函数重载实现。
- 参数化多态:代码没使用任何指定类型实现。利用泛型。
- 子类型多态
Ad hoc polymorphism and Overloading
overload允许在一个类中使用相同的函数名,但参数列表必须不同。静态多态。
可以在同一个类里重载,也可以在子类里重载。
Overload依赖静态检查匹配引用的类型,由引用的类型决定调用的版本。如果子类重载了超类的某个方法,它仍然继承原方法。
第八章:Equality
1.Equivalence Relation
等价关系。

2.Equality of Immutable Types
不可变类型的等价性:
- 根据AF:a = b当且仅当AF(A) = AF(B)
- 根据观察:当两个对象不能用观察加以区分——我们能调用的每一种方法都在两者之上产生相同的效果,则它们等价。
3.Reference equality & Value equality
reference equality:检测两个引用是否指向内存中的同一块区域。Java中利用 == 检验,判断身份标识。
value equality:检测两个对象是否具有相同的值。Java中利用 equals()检验。
对每一个ADT,都要重写Object类的equals()。
由实现者决定对象等价性对于ADT的值究竟意味着什么。
Implement equals()
Object类中的equals()默认判断引用等价性。利用hashcode。
重写Object类的equals时,可能会用到instanceof关键字,判断Object类是否是当前的类的实例。
注意:instanceof除了重写equals,不许在其他地方使用。
Override hashcode
重写equals()的同时必须重写hashcode(),以保证等价对象的hashcode也是相等的。
4.Equality of Mutable Types
- observational equality:在程序的当前状态下,不能区分两个引用。客户端只能通过调用producers和observers来区分两个引用,即”看起来“不同。
- behavioral equality:现在或将来都不能区分两个引用。调用两个对象的任何一个操作,结果都相同
例如:TypeScript中:

- 利用观察等价性:arrayA、arrayB、arrayC等价。
- 利用行为等价性:令arrayA[0] = 0,则arrayA变化,arrayB和arrayC都不变化,说明arrayA与后两个在行为上不等价;令arrayB.pop(),此时后两个的变化情况相同,则它们在行为上也等价。故后两者具有行为等价性。
行为等价性比观察等价性更强,前者的结果需要后者观察。
3570

被折叠的 条评论
为什么被折叠?



