HIT 软构复习中对于ADT的等价性的理解(知识点梳理)

ADT可以大致分为Immutable类型的类和mutable类型的类,软件构造这一节中将ADT的等价性分为两部分去讲,第一部分是Immutable类的等价性,第二部分是mutable类型的类的相关等价性,

首先本节先理清了两个概念,什么是等价性,等价性即是自反,传递和对称。满足以上三个条件的关系即是等价关系。这个对我们如何定义一个类的对象的等价关系(他们如何相等)有很大影响。

首先来看Immutable类型的等价关系。

我们可以通过AF来定义该类的等价关系,也就是说如果R空间的两个对象对应A空间的同一个对象则我们称这两个R空间的对象是等价的。

我们也可以通过调用观察该类的所有方法来定义Immutable类的等价性,即观察等价性,若这两个对象的内容相同则他们就是等价的。

注意这两个等价性并不冲突,在我看来,观察等价性像是对AF等价性的补充和特例。

同时,该章节还注重分析了引用等价性与对象等价性。

引用等价性即为使用==号,也就是等号左右两端的对象的内存地址相同,我们比较基本数据类型时可以使用==,但对象比较时这就是比较两个对象是否是同一个内存下的对象。

而我们常说的对象等价性不同是指的对象的内容相同吗,并不是单单的他们就是同一个对象。

而这在我理解中就是对象等价性。

之后课程在对象等价性的基础又讲到了equals重写方法。

equals方法作为Object类的几个最原始的方法,它的最初是功能是判断对象的引用等价性。

我们在考虑immutable类的等价性时很明显不能只局限于判断他们是不是同一个对象,两个String对象,若他们的字符串相等,我们就应该认为他们两个对象是相等的,而不仅仅是考虑他们是不是同一个对象。

但equals方法有一个坑,他容易被写成重载而不是重写,因此我们需要将要重写的equals方法

前加一个@Override标识符,用于提醒编译器检查。

这是重载,使用最佳匹配原则。

这是正确的重写。

同时需要注意我们在equals方法中通常需要使用instanceof运算符,该运算符功能是判断一个对象是否属于该类,这是属于动态检查的一类。

但最好不要在父类中使用instanceof运算符来匹配子类型。

同时,重写equals方法有这样几条规则。

1.方法判断的“等价”必须是等价关系。

2.equals方法若对象没有改变,则应当调用多次结果是相同的。

3.若重写了equals方法,equals方法保证的所有等价的对象应当由相同的hashcode值。

4.判断null对象时应当返回false。

像通过定义浮点数等价在一个小范围内就不满足等价性。

之后课程解释了关于hashtable的原理,同时也解释了为啥等价的对象一定要有相同的hashcode。

hashtable就是一张表一个大数组,由hashcode寻址,而根据每个对象的特性给出自己的hashcode值,对应一个hashbucket,存在hashbucket内,可在桶内找到它。

我们虽然要求等价的对象有相同的code值,但是对于不同的对象,我们并不要求他们必须不一样,他们可以一样,你可以把所有的hashcode值都设为一个相同的数字,只是这样做性能太差,所有元素都映射为同一个桶中,变成了在桶中的线性查找,性能太差。

这时我们我们就要重写hashcode方法,于我们的equals方法对应。

当然如果你不需要用到hashcode则就不需要重写hashcode方法。

之后我们就来到了mutbale类型的等价性判定。

mutable类型的等价性有两种判定方式:

1.观察等价性,与我们之前提到的Immutable类型的观察等价性类似,使用mutator之外的所有方法得到的结果是一样的,那我们就说这两个对象是等价的。

2.而行为等价性,通俗点说就是指这两个对象是一个对象。对他们无论用什么不同的方法他们反应都一致,包括改变数值。

对于Java的mutable类型,像Collections类equals方法使用的是观察等价性,也就是说他们的当前内容一样,那他们就是相等的,这在实际编程中也是有很大的用处的。

但是像Stringbuilder,他就是使用的行为等价性。

但是观察等价性有个不好之处,这种等价关系是不稳定的,而这种不稳定性导致了一些奇怪的Bug

像下图这个典型例子:

为什么会发生这种情况呢,就是因为观察等价性不稳定,随着一个对象内容的改变这种关系就不复存在了。例子中的list在改之前就加入了set中,根据他的hashcode值被分到了一个桶内,但是我们又改变了它的内容,也就是说它已经不与原来的那个它等价了,这样的话hashcode值通常也就变了,(实际上它也就真变了),我们调用contains方法,它通过hashcode值查找这个list发现新的code值对应的桶中并没有这个list,自然也就返回false了。

那么我们根据这个例子学到了什么呢?

为了避免以上的Bug,对于mutable类型的类不要重写equals方法和hashcode方法了。

也就是直接使用行为等价性即可。(只有两个对象是同一个对象时,这才算等价)

若我们要实现观察等价性(实际上我认为观察等价性是很有用的)就另写一个方法实现它把。

以下是关于两个类的equals与hashcode的最终规定

最后有两个较为重要的知识

1.Java的clone方法是浅克隆,即只是返回一个指向原目标的引用而已。(真懒!)

2.在很多的集合类型的构造器,产生器等等对参数数字进行自动打包,如int类型 2会自动被打包成Integer类型(通常使用Valueof方法)。这有时会引起一些错误。

Java的Valueof方法在数字-128~127范围内不会创建一个新的Integer类型对象,只是多生成一个引用指向给内存而已。

上图对象的创建调用Valueof方法,故输出为1。

而new 则表明开创一块新的内存存放对象,不管是否数字在-128~127之间,故输出为0。

以上就是对软件构造课上ADT的等价性一节的知识点梳理,难免有错误,请大家指正批评!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值