[改善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(与操作)将所有的描述串联起来才能描述一个完整的人,人在不同的环境中角色也在不断的更 ...
随机推荐
- SSH与SSL
1. SSL SSH 即Secure Shell,它主要由三部分组成: 第一部分:连接协议 [SSH-CONNECT] 将多个加密隧道分成逻辑通道.它运行在用户认证协议上.它提供了交互式登录话路.远程 ...
- 您需要来自administrators的权限才能对此文件进行更改
今天我重装了系统,以前D盘里的一个文件夹想删除,可以一直没法删除,原先它提示"您需要来自 S-1-5-21-602162358-1284227242-682003330-500 的权限才能对 ...
- POJ 2349 Arctic Network (最小生成树)
Arctic Network 题目链接: http://acm.hust.edu.cn/vjudge/contest/124434#problem/F Description The Departme ...
- HTTP协议状态码详解
HTTP状态码,我都是现查现用. 我以前记得几个常用的状态码,比如200,302,304,404, 503. 一般来说我也只需要了解这些常用的状态码就可以了. 如果是做AJAX,REST,网络爬虫, ...
- MSSQL索引优化
转自:http://blog.itpub.net/16436858/viewspace-589275/ http://www.cnblogs.com/jams742003/archive/2011/1 ...
- JTextField限制 输入数字
貌似有很多方法,先记了再说... 1.限制输入数字 用法 textfield.setDocument(new IntegerDocument()); class IntegerDocument ext ...
- PostgreSQL的 initdb 源代码分析之十五
继续分析: if (pwprompt || pwfilename) get_set_pwd(); 由于我启动initdb的时候,没有设置口令相关的选项,故此略过. 接下来: setup_depend( ...
- EasyUI基础入门之Parser(解析器)
前言 JQuery EasyUI提供的组件包含功能强大的DataGrid,TreeGrid.面板.下拉组合等.用户能够组合使用这些组件,也能够单独使用当中一个.(使用的形式是以插件的方式提供的) Ea ...
- Codeforces Round #330 (Div. 2)D. Max and Bike 二分 物理
D. Max and Bike Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/595/probl ...
- HDU 4348 To the moon 可持久化线段树,有时间戳的区间更新,区间求和
To the moonTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/view.a ...