软件构造期末复习知识点总结

											ADT和OOP中的“等价性”

一、等价关系
ADT是对数据的抽象,体现为一组对数据的操作,对于抽象数据类型,抽象函数(AF)解释了如何将具体的表示值解释为抽象类型的值,我们看到了抽象函数的选择如何决定如何编写实现每个ADT操作的代码。抽象函数(AF)提供了一种清晰地定义ADT上的等式操作的方法。
在物理世界中,每一个物体都是不同的——在某种程度上,甚至两片雪花也是不同的,即使这种区别只是它们在空间中占据的位置。所以两个物理物体从来没有真正“平等”;它们只有一定的相似程度。然而,在人类语言的世界和数学概念的世界中,你可以为同一事物有多个名字。

二、不可变类型的平等性
利用AF定义等价性,回想一下,抽象函数f:R→A将数据类型的具体实例映射到它们相应的抽象值。-要使用f作为相等式的定义,我们说a等于b当且仅当f(a)=f(b)。等价关系引出了一个抽象函数(关系分区T,因此f将每个元素映射到它的分区类)。由抽象函数引起的关系是一种等价关系。
我们可以谈论抽象值之间的平等性的另一种方式是,一个局外人(一个客户)可以通过观察来观察到关于它们的情况。我们可以说,当两个对象不能通过观察来区分时,它们是相等的——我们可以应用的每个操作都会对两个对象产生相同的结果。
在ADT方面,“观察”是指对对象进行调用的操作。因此,当且仅当它们不能通过调用抽象数据类型的任何操作来区分时,这两个对象才是相等的。

三、== vs. equals()
Java有两个不同的测试相等式的操作,具有不同的语义。运算符可比较引用。它测试参考相等式。如果两个引用指向内存中的同一存储器,则它们是。对于快照图,如果两个引用的箭头指向同一对象气泡,则为==。
equals()操作比较对象内容—换句话说,对象相等。在自定义ADT时,需要重写Object的equals(),当定义新的数据类型时,我们有责任确定数据类型的值的对象等于什么,并适当地实现equals()操作。
对基本数据类型,使用判定相等,对对象类型,使用equals()。如果用,是在判断两个对象
身份标识 ID是否相等(指向内存里的同一段空间)。

四、equals()
equals()方法由对象定义,其默认实现如下:
在这里插入图片描述
当重写equals()方法时,必须遵守其通用合同:
equals必须定义一个等价关系,即一个自反、对称和传递的关系;
除非对象被修改了,否则调用多次equals应同样的结果;
“相等”的对象,其hashCode()的结果必须一致;
自反性:对于任何非空引用值x,x.equals(x)必须返回true。
对称性:对于任何非零引用值x和y,x.equals(y)返回true(x)必须返回true。
传递性:对于任何非空引用值x、y、z,如果x.equals(y)返回true,y.equals(z)返回true,则x.equals(z)必须返回true。
一致性:对于任何非空引用值x和y,x.equals(y)的多个调用始终返回true或始终返回false,但不修改对象的等比较中使用的信息。
对于任何非空引用值x,x.equals(null),必须返回false。

五、hashcode
哈希表是映射的表示:将键映射到值的抽象数据类型。
哈希表是映射的一种表示形式:将键映射到值的抽象数据类型。哈希表提供了持续的时间查找,因此它们往往比树或列表的性能更好。键不必订购,或有任何特定的属性,除了提供等于和散代码。
哈希表的工作方式:它包含一个初始化的数组,大小与我们希望插入的元素数量对应的数组。当显示键和值进行插入时,我们计算键的散希码,并将其转换为数组范围内的索引(例如,通过模除法)。然后,系统会将该值插入到该索引中。哈希表的代表不变量包括键在由其哈希代码决定的插槽中的基本约束。哈希表的rep不变量包含一个基本约束,即键位于由其哈希代码确定的槽中。
在这里插入图片描述

在应用程序执行期间,每当对同一对象多次调用它时,hashCode方法必须始终返回相同的整数,但不修改在该对象的等比较中使用的信息。从应用程序的一次执行到同一应用程序的另一次执行,此整数不必保持一致。等价的对象必须有相同的hashCode,不相等的对象,也可以映射为同样的hashCode,但性能会变差。

六、可变类型的等价性
等价:两个物体不能通过观察来区分时相等。对于可变对象,有两种方法可以解释:当不能通过不改变对象状态的观察来区分它们时,即仅调用观察者、生成者和创建者方法。这通常被严格地称为观测相等,因为它测试了这两个对象在当前的程序状态下“看起来”是否相同。
当它们不能通过任何观察来区分时,甚至状态也会发生变化。这种解释允许调用这两个对象上的任何方法,包括致突变器。这被称为行为平等,因为它测试这两个对象在这个和未来的所有状态下是否“行为”相同。 对可变类型来说,往往倾向于实现严格的观察等价性,但在有些时候,观察等价性可能导致bug,甚至可能破坏RI。
List是一个可变的对象。在像List这样的集合类的标准Java实现中,突变会影响equals()和hashCode()的结果。当列表第一次被放入Hash集时,它被存储在与当时的hashCode()结果对应的哈希桶哈希桶/散列桶中。当列表随后发生突变时,它的hashCode()会发生更改,但HashSet没有意识到应该将其移动到另一个桶中。所以它再也找不到了。当equals()和hashCode()可能受到突变的影响时,我们可以破坏使用该对象作为键的哈希表的代表不变量。
Java对其大多数可变数据类型(如集合)使用观察性等式,但其他可变类(如字符串生成器)使用行为等式。如果两个不同的列表对象包含相同的元素序列,则equals()报告它们相等。
但在有些时候,观察等价性可能导致bug,甚至可能破坏RI
如果某个mutable的对象包含在Set 集合类中,当其发生改变后,集合类的行为不确定。
在JDK中,不同的mutable类使用不同的等价性标准。对可变类型,实现行为等价性即可,也就是说,只有指向同样内存空间的objects,才是相等的。所以对可变类型来说,无需重写这两个函数,直接继承Object的两个方法即可。如果一定要判断两个可变对象看起来是否一致,最好定义一个新的方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值