ADT和OOP中的“等价性”知识点总结

发布时间 2023-05-19 19:56:33作者: Jayhawk

知识点概要:

  • 等价关系
  • 不可变类型的等价性
  • == 与 equals()
  • 实现equals()
  • 对象合同
  • 可变类型的等价性
  • 自动装箱和等价

一、等价关系

  ADT的等价关系是基于AF来定义的

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

二、不可变类型的等价性

  不可变类型的等价性还是依据与AF,AF映射到同样的结果,则等价。这也就是说,站在外部观察者的角度:对两个对象调用任何相同的操作,都得到相同的结果,这样就会认为这两个对象等价。反之亦然。

三、==与equals()

  ==:引用等价性,即如果A==B,则A和B指向内存中同一处地址

  对于基本数据类型,要采用==判定相等。

  equals():对象等价性,即equals会比较对象内容

  由于对于不同的类比较是否等价的条件也不一样,因此,在自定义ADT时,需要重写equals()才能正确的进行equals判断。

  对于对象类型,使用equals()判定相等,如果使用==,是在判断来年各个对象是否指向内存中的同意地址。

四、实现equals()

  这是Object类中默认的equals()函数,在这的equals()是在判断引用等价性,这通常不是程序员所希望的,因此需要重写,以满足对象等价性。

五、对象合同

  除非对象被修改了,否则多次调用equals应得到同样的结果

  “相等”的对象,其hashCode()的结果必须一致

  程序中多次调用同一个对象的hashCode方法,都要返回相同的值

  若两个对象相等,则它们的hashCode相等;反之,若两个对象不相等,则它们的hashCode不相等

  当重写Object中的equals()时,也要重写hashCode()。

六、可变类型的等价性

  在可变类型中,有两种等价性:

  观察等价性:在不改变状态的情况下,两个可变对象是否看起来一致

  行为等价性:调用对象的任何方法都展示出一致的结果

注意:对于不可变对象,观察等价性和行为等价性是相同的,因为没有mutator方法。

  对于可变类型,往往倾向于实现严格的观察等价性。但这也可能导致bug,甚至破坏RI。主要是由于在可变类型的对象包含在HashSet集合中,变量改变后,hashCode也会改变,导致等价性判断失败。

  因此,对于可变类型,实现行为等价性即可,也就是说指向同样内存空间的objects才相等,所以对于可变类型没无需重写equals()和hashCode()方法,直接继承Object中的即可。

  如果一定要判断两个可变类型变量的观察等价性,最好定义一个新的方法。

七、自动装箱和等价

  Java中为每种基本数据类型都提供了对应的包装器类型,让基本类型具备对象的特征,实现更多的功能。

   装箱就是将基本数据类型转换为包装器类型。

  在判断等价中,由于包装器类型是不可变类型,而基本数据类型是可变类型,在装箱与拆箱的过程中就会在判断相等的过程中产生差异。

  就比如:

  

  而x==y 的结果又是False,而再将x和y都转换为int类型,结果又是true。这是基本类型和封装器类型的差异。

  自动装箱的过程又如下所示: