[改善Java代码]在equals中使用getClass进行类型判断
建议47: 在equals中使用getClass进行类型判断
本节我们继续讨论覆写equals的问题。这次我们编写一个员工Employee类继承Person类,这很正常,员工也是人嘛,而且在JEE中JavaBean有继承关系也很常见,代码如下:
public class Client {
public static void main(String[] args) {
Employee e1 = new Employee("张三",100);
Employee e2 = new Employee("张三",1001);
Person p1 = new Person("张三");
System.out.println(p1.equals(e1));
System.out.println(p1.equals(e2));
System.out.println(e1.equals(e2));
}
}
class Person{
private String name;
public Person(String _name){
name = _name;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Person){
Person p = (Person) obj;
return name.equalsIgnoreCase(p.getName().trim());
}
return false;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Employee extends Person{
private int id;
/*id的getter/setter方法省略*/
public Employee(String _name,int _id) {
super(_name);
id = _id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Employee){
Employee e = (Employee) obj;
return super.equals(obj)&& e.getId() == id;
}
return false;
}
}
输出结果:
true
true
false
很不给力嘛,p1竟然等于e1,也等于e2,为什么不是同一个类的两个实例竟然也会相等呢?这很简单,因为p1.equals(e1) 是调用父类Person的equals方法进行判断的,它使用instanceof关键字检查e1是否是Person的实例,由于两者存在继承关系,那结果当然是true了,相等也就没有任何问题了,但是反过来就不成立了,e1或e2可不等于p1,这也是违反对称性原则的一个典型案例。
更玄的是p1与e1、e2相等,但e1竟然与e2不相等,似乎一个简单的等号传递都不能实现。这才是我们要分析的真正重点:e1.equals(e2)调用的是子类Employee的equals方法,不仅仅要判断姓名相同,还要判断工号是否相同,两者工号是不同的,不相等也是自然的了。等式不传递是因为违反了equals的传递性原则,传递性原则是指对于实例对象x、y、z来说,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。
这种情况发生的关键是父类使用了instanceof关键字,它是用来判断是否是一个类的实例对象的,这很容易让子类“钻空子”。想要解决也很简单,使用getClass来代替instanceof进行类型判断,Person类的equals方法修改后如下所示:
public boolean equals(Object obj) {
if(obj!=null && obj.getClass() == this.getClass()){
Person p = (Person) obj;
if(p.getName()==null || name==null){
return false;
}else{
return name.equalsIgnoreCase(p.getName());
}
}
return false;
}
当然,考虑到Employee也有可能被继承,也需要把它的instanceof修改为getClass。总之,在覆写equals时建议使用getClass进行类型判断,而不要使用instanceof。
[改善Java代码]在equals中使用getClass进行类型判断的更多相关文章
- [改善Java代码]减少HashMap中元素的数量
在系统开发中我们经常会使用HashMap作为数据集容器,或者是用缓冲池来处理,一般很稳定,但偶尔也会出现内存溢出的问题(OutOfMemory错误),而且这经常是与HashMap有关的.而且这经常是与 ...
- [改善Java代码]注意方法中传递的参数要求(replaceAll和replace的区别)
有这样一个简单的需求:写一个方法,实现从原始字符串中删除与之匹配的所有子字符串,比如"蓝蓝的天,白云飘"中,删除"白云飘",输出"蓝蓝的天," ...
- [改善Java代码]在接口中不要存在实现代码
第3章 类.对象及方法 书读得多而不思考,你会觉得自己知道的很多. 书读得多而思考,你会觉得自己不懂的越来越多. —伏尔泰 在面向对象编程(Object-Oriented Programming,O ...
- C#保留2位小数几种场景总结 游标遍历所有数据库循环执行修改数据库的sql命令 原生js轮盘抽奖实例分析(幸运大转盘抽奖) javascript中的typeof和类型判断
C#保留2位小数几种场景总结 场景1: C#保留2位小数,.ToString("f2")确实可以,但是如果这个数字本来就小数点后面三位比如1.253,那么转化之后就会变成1.2 ...
- [改善Java代码]覆写equals方法必须覆写hashCode方法
覆写equals方法必须覆写hashCode方法,这条规则基本上每个Javaer都知道,这也是JDK API上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢?本建议就来解释该问题,我们先 ...
- [改善Java代码]避开基本类型数组转换列表陷阱
开发中经常用到Arrays和Collections这两个工具类. 在数组和列表之间进行切换.非常方便.但是也会遇到一些问题. 看代码: import java.util.Arrays; import ...
- [改善Java代码]注意Class类的特殊性
Java语言是先把Java源文件编译成后缀为class的字节码文件,然后再通过ClassLoader机制把这些类文件加载到内存中,最后生成实例执行的,这是Java处理的基本机制,但加载到内存中的数据是 ...
- [改善Java代码]列表相等只需关系元素数据
来看一个判断列表相等的例子,看代码: import java.util.ArrayList; import java.util.Vector; public class Client { public ...
- [改善Java代码]严格限定泛型类型采用多重界限
从哲学上来说,很难描述一个具体的人,你可以描述它的长相,性格,工作等,但是人都是有多重身份的,估计只有使用多个And(与操作)将所有的描述串联起来才能描述一个完整的人,人在不同的环境中角色也在不断的更 ...
随机推荐
- JavaScript——对this指针的新理解
一直以来对this的理解只在可以用,会用,却没有去深究其本质.这次,借着<JavaScript The Good Parts>,作了一次深刻的理解.(所有调试都可以在控制台中看到,浏览器F ...
- bitmap的实现方法
bitmap是一个十分有用的结构.所谓的Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素.由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省. 适用 ...
- JSF 2.0 hello world example
In this tutorial, we will show you how to develop a JavaServer Faces (JSF) 2.0 hello world example, ...
- jQuery基础学习3——jQuery库冲突
默认情况下,jQuery用$作为自身的快捷方式. jQuery库在其他库之后导入 在其他库和jQuery库都被加载完毕后,可以在任何时候调用jQuery.noConflict()函数来将变量$的控制权 ...
- hashCode()和equals()的用法
使用hashCode()和equals() hashCode()和equals()定义在Object类中,这个类是所有java类的基类,所以所有的java类都继承这两个方法. hashCode()方法 ...
- Unity3D中关于场景销毁时事件调用顺序的一点记录
先说一下我遇到的问题,我弄了一个对象池管理多个对象,对象池绑定在一个GameObject上,每个对象在OnBecameInvisible时会进行回收(即移出屏幕就回收),但是当场景切换或停止运行程序时 ...
- HDU 5235 Friends (2015 Multi-University Training Contest 2 搜索+剪枝)
题目链接:pid=5305">传送门 题意: n个人给定m个关系.每一个关系为x,y表示x,y是朋友.可是可能是online friends,也可能是offline friends. ...
- MyEclipse 8.5 Axis2 插件完整jar包
http://download.csdn.net/download/hob007/4457837 MyEclipse 8.5 安装 Axis2 插件所需的完整JAR包 两个axis2插件,以及三个ja ...
- 详解Android Handler的使用-别说你不懂handler
我们进行Android开发时,Handler可以说是使用非常频繁的一个概念,它的用处不言而喻.本文就详细介绍Handler的基本概念和用法. Handler的基本概念 Handler主 ...
- MySQL 行子查询(转)
MySQL 行子查询 行子查询是指子查询返回的结果集是一行 N 列,该子查询的结果通常是对表的某行数据进行查询而返回的结果集. 一个行子查询的例子如下: SELECT * FROM table1 WH ...