第七章 面向对象的编程
面向对象编程,个人理解就是针对特定的对象进行操作,对象包含状态和行为
例如C语言中整数运算,是按流程进行操作,而在Java中,就可能先定义一个对象(假设命名为整数,该对象内部就有其状态和行为。这种设计使得面向对象有很好的复用性
当成员变量或方法用static修饰时,说明该变量或方法属于类而不属于实例,所以无需通过创建实例即可调用,例如System.out.println
7.1接口interface
接口就是特殊的类
– Interface和Class: 定义和实现ADT
– 接口中只有方法的定义,没有实现
– 接口之间可以继承与扩展
– 一个类可以实现多个接口(从而具备了多个接口中的方法)
– 一个接口可以有多种实现类
最新的接口为保证安全性,内部可以实现constructor
7.1.1接口中的每个方法在所有类中都要实现,缺点是会导致部分方法的重复实现
通过default方法,在接口中统一实现某些功能,无需在各个类中重复实现它.也就是可以将确定的实现方法放在接口中,而后续的实现类中就无需重复实现
7.1.2封装和信息隐藏
使用接口类型声明变量,客户端仅使用接口中定义的方法,客户端代码无法直接访问属性
使用修饰
7.2多态
7.2.1特殊多态 方法重载
进行静态类型检查,参数列表必须不同
可以在同一个类内重载,也可在子类中重载
重载和重写
重写时父类和子类中的方法具有相同的签名,签名不同时则为重载
子类重载了父类的方法后,子类仍然继承了被重载的方法
7.2.2 参数多态 泛型
参数多态性是指方法针对多种类型时具有同样的行为(这里的多种类型应具有通用结构),此时可使用统一的类型变量表达多种类型
在运行时根据具体指定类型确定具体类型(编译成class文件时,会用指定类型替换类型变量“擦除”)
也就是说,运行中无泛型
使用泛型变量的三种形式:泛型类、泛型接口和泛型方法
泛型接口又分为泛型和非泛型实现类
非泛型
泛型
Wildcards 通配符
– List<?> list = new ArrayList<String>();
– List<? extends Animal> 表示Animal的所有子类
– List<? super Animal> 表示Animal的所有父类
7.2.3 子类型多态
一个类只有一个父类,但可以实现多个接口
子类型的规约不能弱化超类型的规约
子类型多态:不同类型的对象可以统一的处理而无需区分,从而隔离了“变化”
第八章 ADT和OOP中的“等价性”
8.1等价关系
两种定义等价的方法
8.1.1基于抽象函数AF定义ADT的等价操作
如果AF映射到同样的结果,则等价
8.1.2站在外部观察者角度:
对两个对象调用任何相同的操作,都会得到相同的结果,则认为这两个对象是等价的。
8.2== vs. equals()
== 引用等价性
.equals() 对象等价性
一般来说对基本数据类型,使用==判定相等。对对象类型,使用equals()。
==判断的是两个变量指向的内存空间是否相等
而object中的.equal就是使用==实现,而程序员通常希望判断内容是否相等,例如Person n和Person m里面的属性是否相等,所以对于大部分情况下类的equal要重写
instanceof:判断某个对象是不是特定类型(或其子类型) getclass也有类似功能
8.3关于hash
当使用到hashmap或者hashset等容器时,要保证等价的对象必须有相同的hashCode
hashCode与equal一样是object自带,不使用与hash相关的时候无用
为保证hashcode相同,在重写equal时也应该重写hashcode
8.4可变类型的等价性
对于不可变类型,它的等价一定是行为等价的
观察等价性:在不改变状态的情况下,两个mutable对象是否看起来一致
行为等价性:调用对象的任何方法都展示出一致的结果
object默认是行为等价,如果一定要判断两个可变对象看起来是否一致,最好定义一个新的方法。
总结
对于不可变类型:
- equals() 应该比较抽象值。与说 equals() 应该提供行为等价是一样的。
– hashCode() 应该将抽象值映射到一个整数。
– 所以不可变类型必须同时覆盖 equals() 和 hashCode() 。
对于可变类型:
– equals() 应该比较引用,就像 == 一样。与说 equals() 应该提供行为等价是一样的。
– hashCode() 应该将引用映射为整数。
– 所以可变类型根本不应该覆盖 equals() 和 hashCode(),而应该简单地使用 Object 提供的默认实现。
PPT第七部分不甚理解
第九章 面向复用的软件构造技术
–源代码级别的复用
–模块级别的复用:类/抽象类/接口
–库级别的复用:API/包
–系统级别的复用:框架
面向复用编程:开发出可复用的软件
基于复用编程:利用已有的可复用软件搭建应用系统
面向复用编程一般要比面向应用编程更复杂
代码复用就是合理copy,不在赘述
9.1模块级别复用
又要提到子类型多态:客户端可用统一的方式处理不同类型的对象
就例如
9.1.1 LSP原则
子类型可以增加方法,但不可删
子类型需要实现抽象类型 (接口、抽象类)中所有未实现的方法
子类型中重写的方法必须有相同或子类型的返回值或者符合co-variant的参数
类型中重写的方法必须使用同样类型的参数或者符合contra-variant的参数(此种情况Java目前按照重载overload处理)
子类型中重写的方法不能抛出额外的异常
在具体程序子类型中体现为
前置条件不能强化后置条件不能弱化
不变量要保持
子类型方法参数:逆变 子类型方法的返回值:协变
异常类型:协变
java中把参数逆变协变都当重载
Java中数组是协变的: 对T[]数组,可以保存类型T及其子类型的数据
泛型中的LSP
泛型是类型不变的,运行时类型擦除,此时类型确定
所以
但可采用通配符实现两个泛型类的协变
List<?>. 无限定通配符?
本意是期望可打印任意类型的List,但由于泛型不协变,只能打印List<Object>
修改为
<? super A> 下限通配符 A的所有父类
<? extends A> 上限通配符 A的所有子类
当有了 通配符后,泛型就可以实现协变
9.2继承和委托/委派 也属于模块级别复用
委派/委托:一个对象请求另一个对象的功能
如果子类只需要复用父类中的一小部分方法,可以不需要使用继承,而是通过委派机制来实现
如果一个类不需要继承另一个类的全部方法,通过委托机制调用部分方法,从而避免继承大量无用的方法
委派类型 依赖 关联 组合/聚合
9.3设计可重用 API 库和系统级框架
API库是程序员设计开发的一组提供可重用功能的类和方法 (API)
白盒框架和黑盒框架
白盒中子类中由开发者通过override完成定制的功能
黑盒中由开发者完成委派的对象完成定制功能