Chapter3:抽象数据类型(ADT)和面向对象的编程(OOP)
3.5ADT和OOP中的等价性(Equality in ADT and OOP)
1.等价关系(Equivalenve Relation)
等价关系:自反,对称,传递
2.判断等价性的两种方法。
- 抽象函数AF:AF(a)=AF(b);
- 利用观察者Observation.
3.==和.equals()的区别
- ==比较的是地址
- .equals()比较的是内容
在自定义ADT时,需要根据对“等价”的要求,决定是否重写Object的equals();
4.实现.equals()
注意:
- 实现equals需要使用重写(override),而不能使用重载(overload)。
- 重写是动态检查,重载是静态检查,重载在编译时就决定使用哪个。
例子一:使用重载会发生的问题。
当Object o2=d2后; d1.equals(o2)显示为错,因为o2在编译阶段就决定使用了原先的方法,比较的是地址,所以出现false。
例子二:.equals()重写的方法
instanceof用法注意:
- 作用:判断某个对象时不是特定类型(或其子类型)。
- 动态类型检查,运行的时候判断。即Object a=new Horse();a在运行时为Horse类。
- 除了用于实现equals()方法,尽可能避免使用instanceof和getClass()。
instanceof错误用法的例子:
原因是以后有更多的子类需要一个个进行书写,当一个子类进行更改时,需要对instanceof内部代码进行修改,容易造成很多问题。
使用重写来避免使用instanceof
acct无论是哪种子类,通过重写,用相同的方法,可以返回不同的值,带来了极大的便利性。
5.对象契约(The Object contract)
**equals()相等:**相等的对象,其hashCode()的结果必须一致。
HashTable工作原理: 键值中的key被映射为hashcode,对应到数组的index,hashcode决定了数据被存储到数组的哪个位置。
HashCode重写的两个例子:
6.可变类型的等价性(Equality of Mutable Types)
- 观察等价性:在不改变状态的情况下,两个mutable对象看起来一致。
- 行为等价性:调用对象的任何方法展示出一致的结果。
但在有些时候,观察等价性可能导致bug,甚至可能破坏RI。
例子:
在这个例子中,先生成一个新的list,然后list.add(a),再将list加入到一个set中。set.contains(list)为真,而再向list中加一个元素,set.contains(list)为假。
**可变类型观察等价性出现bug的原因:**对象的hashcode变了,但是HashSet没有更新其在bucket的位置,查找时在新hashcode的位置找不到元素。
对于可变类型(地址空间不会改变):
- 实现行为等价性即可。
- 只有指向同样内存空间的objects,才是相等的。
- 无需重写equals(),hashcode()两个函数,直接继承Object两个方法即可。
- 如果一定要判断两个可变对象是否一致,最好定义一个新的方法。
可变类型使用不同的等价性标准:
对于不可变类型:
- 必须重写equals(),hashcode()两个函数.
equals的行为等价性和观察等价性:
- equals的行为等价性是判定地址是否相同
- 观察等价性是判定特定内容是否相同
**例题:**Bag是一个可变类型,分别利用equals的行为等价性和观察等价性进行判定是否相同。
可以用.clone()进行复制
7.自动包装和等价性(Autoboxing and Equality)
几段代码:
- 只要数值相等,调用.equals都相等。
- Integer a=new Integer(2)为a创建了新的地址空间,所以==不相等。
- Integer a=2,没有为a创建新的地址空间,而是直接将a指向了编译器已经创建好的地址空间。(-128~127java为部分常数创建好了地址空间),所以==比较相等。
- Integer a=128,将重新给a创建地址空间,所以==比较不相等。
- Integer a=new Integer(2),而是用(int)a==进行比较时相等,因为转为int型,进行=比较的时候比较的是值的大小,所以=比较相等
Integer a=new Integer(128);
Integer b=new Integer(128);
System.out.println(a==b); //false
System.out.println(a.equals(b));//true
--------------------------------------------------
Integer a=new Integer(2);
Integer b=new Integer(2);
System.out.println(a==b); //false
System.out.println(a.equals(b));//true
--------------------------------------------------
Integer a=2;
Integer b=2;
System.out.println(a==b); //true
System.out.println(a.equals(b));//true
--------------------------------------------------
Integer a=128;
Integer b=128;
System.out.println(a==b); //false
System.out.println(a.equals(b));//true
--------------------------------------------------
Integer a=128;
Integer b=128;
System.out.println((int)a==(int)b);//true
System.out.println(a.equals(b));//true