欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

软件构造3.5ADT和OOP中的“等价性”

程序员文章站 2022-07-14 21:42:28
...

Chapter3:抽象数据类型(ADT)和面向对象的编程(OOP)

3.5ADT和OOP中的等价性(Equality in ADT and OOP)

1.等价关系(Equivalenve Relation)

等价关系:自反,对称,传递

2.判断等价性的两种方法。

  1. 抽象函数AF:AF(a)=AF(b);
  2. 利用观察者Observation.

3.==和.equals()的区别

  • ==比较的是地址
  • .equals()比较的是内容

在自定义ADT时,需要根据对“等价”的要求,决定是否重写Object的equals();

4.实现.equals()

注意:

  1. 实现equals需要使用重写(override),而不能使用重载(overload)。
  2. 重写是动态检查,重载是静态检查,重载在编译时就决定使用哪个。

例子一:使用重载会发生的问题。
当Object o2=d2后; d1.equals(o2)显示为错,因为o2在编译阶段就决定使用了原先的方法,比较的是地址,所以出现false。
软件构造3.5ADT和OOP中的“等价性”

例子二:.equals()重写的方法
软件构造3.5ADT和OOP中的“等价性”
instanceof用法注意:

  1. 作用:判断某个对象时不是特定类型(或其子类型)。
  2. 动态类型检查,运行的时候判断。即Object a=new Horse();a在运行时为Horse类。
  3. 除了用于实现equals()方法,尽可能避免使用instanceof和getClass()。

instanceof错误用法的例子:
原因是以后有更多的子类需要一个个进行书写,当一个子类进行更改时,需要对instanceof内部代码进行修改,容易造成很多问题。
软件构造3.5ADT和OOP中的“等价性”
使用重写来避免使用instanceof
acct无论是哪种子类,通过重写,用相同的方法,可以返回不同的值,带来了极大的便利性。
软件构造3.5ADT和OOP中的“等价性”

5.对象契约(The Object contract)

**equals()相等:**相等的对象,其hashCode()的结果必须一致。
HashTable工作原理: 键值中的key被映射为hashcode,对应到数组的index,hashcode决定了数据被存储到数组的哪个位置。
软件构造3.5ADT和OOP中的“等价性”
HashCode重写的两个例子:
软件构造3.5ADT和OOP中的“等价性”
软件构造3.5ADT和OOP中的“等价性”

6.可变类型的等价性(Equality of Mutable Types)

  1. 观察等价性:在不改变状态的情况下,两个mutable对象看起来一致。
  2. 行为等价性:调用对象的任何方法展示出一致的结果。

但在有些时候,观察等价性可能导致bug,甚至可能破坏RI。
例子:
    在这个例子中,先生成一个新的list,然后list.add(a),再将list加入到一个set中。set.contains(list)为真,而再向list中加一个元素,set.contains(list)为假。

软件构造3.5ADT和OOP中的“等价性”
**可变类型观察等价性出现bug的原因:**对象的hashcode变了,但是HashSet没有更新其在bucket的位置,查找时在新hashcode的位置找不到元素。

对于可变类型(地址空间不会改变):

  1. 实现行为等价性即可。
  2. 只有指向同样内存空间的objects,才是相等的。
  3. 无需重写equals(),hashcode()两个函数,直接继承Object两个方法即可。
  4. 如果一定要判断两个可变对象是否一致,最好定义一个新的方法。

可变类型使用不同的等价性标准:
软件构造3.5ADT和OOP中的“等价性”

对于不可变类型:

  1. 必须重写equals(),hashcode()两个函数.

equals的行为等价性和观察等价性:

  • equals的行为等价性是判定地址是否相同
  • 观察等价性是判定特定内容是否相同

**例题:**Bag是一个可变类型,分别利用equals的行为等价性和观察等价性进行判定是否相同。
软件构造3.5ADT和OOP中的“等价性”
可以用.clone()进行复制
软件构造3.5ADT和OOP中的“等价性”

7.自动包装和等价性(Autoboxing and Equality)

几段代码:

  1. 只要数值相等,调用.equals都相等。
  2. Integer a=new Integer(2)为a创建了新的地址空间,所以==不相等。
  3. Integer a=2,没有为a创建新的地址空间,而是直接将a指向了编译器已经创建好的地址空间。(-128~127java为部分常数创建好了地址空间),所以==比较相等。
  4. Integer a=128,将重新给a创建地址空间,所以==比较不相等。
  5. 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 
相关标签: 软件构造