Java getClass()与instanceof的区别以及如何编写一个完美的equals()和hashCode()方法
1、首先我们来看下Java规范中的equals()要求有哪些特性
自反性
对于任何非空引用有 x.equals(x)=true
对称性
y.equals(x)=true;x.equals(y)=true
传递性
x.equals(y)=truy ; y.equals(z)=true;则x.equals(z)=true
一致性
如果x,y的引用没有发生变化,则反复调用x.equals()方法应该得到相同的结果
对于任何非空引用x,有x.equals(null)的结果为false
2、getClass()与instanceof在equals()方法中的区别
方法 | 解释 |
---|---|
getClass() | 返回当前对象的类的类型 |
instanceof | 用于判断某个对象是否属于属于这个类或者其父类 |
首先我们来看下面一个超级简单的测试代码
测试结果
从以上的结果我们可以看出什么呢?
注意,其中最大的一个区别就是 child instanceof Father = true
而father instanceof Child = false
,并且只有child.getClass()=child.getClass();father.getClass()=father.getClass()
3、编写equals()的完美方法
知道了第二步中的结果,先别急,让我们看看编写equals的正确方法先
首先我们有x.equals(otherObject)
1、检测this与otherObject是不是同一个对象
if(this==otherObject)return true
2、 检测otherObject是不是null
if(otherObject==null)return false
3、比较this与otherObject是否属于同一个类,如果equals()方法在子类中被重写且与父类的equals()方法不同,则使用
if(getClass()!=otherObject.getClass)return false
否则使用(ClassName代表当前类的类名)
if(!(otherObject instanceof ClassName))return false
4、将otherObject转化为这个类的类型
otherObject=(ClassName)otherObject
5、对对象中的属性值进行比较
return Objects.equals(field,otherObject.field)&&Objects.equals(field2,otherObject.field2)...
4、简单分析
好,以上equals()的方法讲完了,我相信你现在肯定有着很多疑惑,没事让我简单的和你说一下这个道理。其实equals的比较方法和我们现实生活中的道理是一样的,比如说我们要比较两个铅笔盒。首先我们判断这两个铅笔盒是不是同一个铅笔盒,如果是那就直接相等。然后我们在判断第二个铅笔盒存在吗?如果不存在,那就是说比较的对象都没有,那肯定返回false;然后我们要判断这两个铅笔盒外表是不是长得一样呀,也就是说他们是不是同一类型,当然我们这里还需要考虑子类和父类的情况,好,如果这两个铅笔盒外表一样,那么接下来我们就要看这两个铅笔盒中的铅笔是不是都一样呀;
这样我们就完成了一个简单的equals()方法;
那么最令人疑惑的地方是哪里呢?本人当初最疑惑的点是第三步中getClass()与instanceof的选择,让我困惑了好长一段时间,这也是我为什么写这篇博客的真正原因。
5、getClass()与instanceof分析解释
我们再来仔细回顾一下,在第三步方法中的描述,如果子类中的equals方法和父类中的equals()方法的的比较规则不一样,这个时候就要使用getClass()了。那好在解释这句话之前我们先来看一段代码
代码很简单,我们可以看到有一个父类Car它有一个属性run,子类SuperCar有一个额外的属性superPower;好,现在我们来看他们的equals()方法
我们看到父类是完全按照以上给出的方法完成的,值得注意的是它用的是getClass();
好,现在我们来判断一下我们在子类对象中调用equals(f父类对象)方法会发生什么,首先他会调用父类的equal(),由于父类的equals()方法中此时持有的是子类的this隐式参数,也就是说此时父类中的这行代码getClass()
得到的结果是子类的类型,而方法参数中的类型是Car类型,那显然他们不相等。
有点累了,在这里我把心法传给你吧!
子类重新定义了equals()方法往往意味着这个子类中有父类没有的东西,也就是说光是父类的比较方法已经满足不了我了,这个时候我们采取的策略是子类只能和子类比较,子类和父类比较统统是false,这也正是getClass()的作用,其实也很好理解,子类拥有比父类更多的东西,你父类都没有,那我们还比什么,所以这里你应该懂了什么时候用getClass()什么时候用instanceof了。再插一句,那么当我们子类没有比父类更多的东西时,那么我子类当然理所应当能和你父类正常比较啦