最近,在我复习的时候对于等价性这个问题掌握的不是很好,尤其是有关于重写equals()方法的时候不能够很好地理解。
等价性
等价这个概念最早是在《离散数学》这门课中接触到的,它有三个要素:
1.自反性: 任意x属于A,则x与自己具有关系R,即xRx;
2.对称性: 任意x,y属于A,如果x与y具有关系R,即xRy,则y与x也具有关系R,即yRx;
3.传递性: 任意x,y,z属于A,如果xRy且yRz,则xRz
这是在那一门课中给出的定义,而在这一门科中,我们也延展了这种定义:AF映射到同样的结果,则等价。这也就是说,如果对两个对象用任何相同的操作,得到的结果如果是相同的话,那么就可以认为这两个对象是等价的。
并且,在这门课中,等价性还有着不同的分类:
==和.equals()
在没有接触到这一门课时候,我们在判断两个变量是否相等的时候只会用到==,但是之后学了这门课,并且了解了各种类型在计算机中的储存原理之后,发现‘==’并不能总是很好的反应等价这个性质。
所以,这门课中引入了.equals()这个方法,==强调的是引用等价性,而.equals()代表了对象等价性,从这两个名字上就能看出他们的区别:一个是对于引用的值,指向内存里的同一段空间;一个面向的是对象,它对应的是这个对象的一些性质。
重写equals()
在大多数情况下,我们更倾向于用.equals()来比较两个对象是否等价,但是,由于在Object类之中,方法的实现也只是用了==即引用等价性来实现的,所以这就需要我们完成对该方法的重写。
在重写的时候需要注意.equals()满足的那三个性质:
例如:
标准的.equals()写法:.
@Override
public boolean equals(Object obj) {
if(obj == this) {
return true;
}
if(!(obj instanceof Class)) {
return false;
}
Class m1 = (Class) obj;
return m1 .ocpp1 == ocpp1 &&
m1 .ocpp2 == ocpp2;
}
这就满足了那三条性质。
在某些时候,我们可能忽略了某种性质,是的.equals并不满足等价的条件:
public boolean equals(Object o) {
if(!(o instanceof Class))
return false;
Class cp = (Class)o;
return super.equals(o) && cp.Classname== Classname;
}
这里有一个父类的.equals,这就会使得当父类和子类进行.equals比较的时候出现不同的结果,最终违反了对称性。
public boolean equals(Object o) {
if(!(o instanceof Class))
return false;
if(!(o instanceof Classex))
return o.equals(this);
Classexcp = (Classex)o;
return super.equals(o) && cp.Classname== Classname;
}
将上面的那个方法修改之后,就是的.equals满足了对称性,但是它又不满足传递性,这是因为在比较的语句中走入了不同的分支,这样就会出现A.equals(B)和B.equals(C)为True,但是A.equals(C)为false的情况。
所以,在重写.equals()方法的时候一定要万分的小心。
之后,完成了这个方法的重写之后,也要注意hashcode方法的改写,两个equal的objects,一定要有同样的hashcode。两个不equal的objects,不一定要有同样的hashcode。
观察等价性和行为等价性
对于可变数据类型,他们有着mutator方法,所以,在判断他们之间的等价性问题的时候就有两种思考方式,一种是观察他们本身是否一致,一种是对于他们的各种方法在进行相同的操作之后,表现出的结果是否一致。所以,这就有了观察等价性和行为等价性两个概念:
观察等价性:在不改变状态的情况下,两个mutable对象是否看起来一致。
行为等价性:调用对象的任何方法都展示出一致的结果。
对可变类型来说,往往倾向于实现严格的观察等价性,但是这是很难实现的,而且,实现的过程中会带来很多问题。
所以,不同的集合类Java的设计者实现了不同的等价性。Date类实现了观察等价性,List类观察等价性,而StringBuilder类直接继承了Object类,实现了行为等价性。
而对于我们自己所编写的可变类型来说,实现行为等价性就可以了,这就可以直接继承Object类中对应的方法,这大大降低了难度,很方便。
综上,等价性问题还是很复杂的,这需要我们细心体会其中的差异,这样才能保证我们自己重写出的方法满足等价性的条件。