软件构造学习笔记第三章
Mutable/Immutable
可变性
改变一个变量 将变量指向另一个存储空间
改变一个变量的值 向该变量当前指向值的存储空间中添加一个新值
Immutability 不变性
不能被改变的数据类型 一旦被创建其值再不能被改变
引用类型 一旦确定指向对象 就不可以改变
Final关键字 若java编译器不能确定final修饰的变量会不会改变就会报错,这也属于静态检查
Final修饰类 无法再产生子类 修饰变量 无法改变其值或者引用 修饰方法 则该方法不能被重写
可变对象拥有一个可以改变自己的值或者 引用的方法,而不可变对象没有
可变类型的有点
- 使用不可变类型,需要进行大量的临时拷贝
- 可变类型可以最小化拷贝以提高效率
- 可以获得更好的性能
- 适合于在多个模块之间的共享数据
不可变类型 更安全,更好理解,对改变的支持也更好
常见可变类型 StringBuilder,Date,List<>
常见的不可变类型 LocalDateTime Instant 基本类型及其封装类型
UnmodifiableList unmodifiableSet unmodifiableMap 不可改变
它们接收一个List Set Map ,包装为一个不可变List 如 List
Snapshot diagram快照图 runtime code-level moment
基本类型的值
对象类型的值 一个椭圆圈
不可变对象 用双线椭圆圈表示
不可变引用 用双线箭头表示
Iterator对一个List进行遍历的时候,不可以改变List之中的元素,即remove add 等,否则编译器在运行时会报错
即不可对原数组进行直接操作,但是可以使用iterator自带的remove函数
表示独立性
用户使用ADT时没有必要考虑ADT内部如何实现,ADT内部表示的变化不会影响spec和客户端
表示泄露
表示不变量 RI
不变量 ADT中无论如何都要成立的部分 由ADT来完全负责自己的表示不变量, 使用表示不变量来检查程序的正确性
使用private final 来保证RI不变量的方法
使用防御性copy 返回mutable类型时 将该内容copy到一个新的对象中返回
继承:Override
Rewriteable Methods 可以被重新实现的方法
严格继承:子类中只能添加新的方法 但是无法重写超类中的方法
Java中不能被重写的方法需要在声明中加入final关键字
Final field 代码初始化之后无法被重新赋值
Final method 防止这个方法被重写
Final class 防止类的继承
重写函数与原函数有一样的函数声明super可以调用父类函数的功能 在构造函数中super只能放在第一排
多态: overload
多态的三种类型
1 特殊多态 功能重载
2 参数多态
3 子类型多态,包含多态
子类重载的函数 父类是可以调用的
Equals的自反,传递,对称
等价的三种定义方式
- 若 AF映射到同样的结果,则等价
- 若两个对象之间满足自反传递对称的关系,那么为等价关系
- 站在外部观察者角度发展二者没有区别
- 站在外部观察者的角度发现二者没有区别
对于ADT来说,“观察”就表示调用该类的运算符 - 除非对象被修改 否则多次调用该对象得到的结果应该是一样的
- Hashcode() 返回结果必须一致 相等的对象
- A.equal(null) 一定返回false
Hashcode 和equals 一起被重写
17 31 法则 这两个比较大的质数
Immutable 使用观察等价性(观察等价性和行为等价性相等)
Mutable 主要使用行为等价性(集合类使用观察等价性)
可变观察对象的观察等价性和行为等价性
Object中缺省使用“==”来判断两个对象是否相同
Instanceof操作应该只在equals方法内使用
观察等价性,在不改变状态的情况下,两个mutable对象是否看起来一致
调用observer producer creater 对比两者的状态
行为等价性,调用对象的任意方法,都展现出一致的结果
对于可变对象来说往往倾向于实现严格的观察等价性
有时候观察等价性可能会导致bug
如果某个mutable对象包含在集合类当中当其发生改编后集合类的行为不确定
Collection 使用观察等价性
Stringbuilder 使用行为等价性
对于mutable对象无需重写hashcode() equals()保留缺省值即可