java重写equals方法
@Override
public int hashCode() {
return task.getId();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof TaskHandlerTimer) {
TaskHandlerTimer oo = (TaskHandlerTimer) obj;
if (this.task.getId() == oo.task.getId())
return true;
}
return false;
}
为什么equals()方法要重写?
判断两个对象在逻辑上是否相等,如根据类的成员变量来判断两个类的实例是否相等,而继承Object中的equals方法只能判断两个引用变量是否是同一个对象。这样我们往往需要重写equals()方法。
我们向一个没有重复对象的集合中添加元素时,集合中存放的往往是对象,我们需要先判断集合中是否存在已知对象,这样就必须重写equals方法。
怎样重写equals()方法?
重写equals方法的要求:
1、自反性:对于任何非空引用x,x.equals(x)应该返回true。
2、对称性:对于任何引用x和y,如果x.equals(y)返回true,那么y.equals(x)也应该返回true。
3、传递性:对于任何引用x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。
4、一致性:如果x和y引用的对象没有发生变化,那么反复调用x.equals(y)应该返回同样的结果。
5、非空性:对于任意非空引用x,x.equals(null)应该返回false。
1、自反性原则
在JavaBean中,经常会覆写equals方法,从而根据实际业务情况来判断两个对象是否相等,比如我们写一个person类,根据姓名来判断两个person类实例对象是否相等。代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public class Person { private String name; public Person(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object obj) { if (obj instanceof Person) { Person person= (Person) obj; return name.equalsIgnoreCase(person.getName().trim()); } return false; } public static void main(String[] args){ Person p1=new Person("张三"); Person p2=new Person("张三 "); List<person> list = new ArrayList<person>(); list.add(p1); list.add(p2); System.out.println("是否包含张三:"+list.contains(p1)); System.out.println("是否包含张三:"+list.contains(p2)); }}</person></person> |
list中含有这个生成的person对象,结果应该为true,但是实际结果: 这里考虑了字符串空格的问题,去除前后的空格。
是否包含张三:true
是否包含张三:false
第二个为什么会是false呢?原因在于list中检查是否含有元素时是通过调用对象的equals方法来判断的,也就是说 contains(p2)传递进去会依次执行p2.equals(p1)、p2.equals(p2),只要一个返回true,结果就是true。但是这里p2.equals(p2)返回的是false?由于我们对字符前后进行了空格的切割造成p2.equals(p2)的比较实际上是:“张三 ”.equals(“张三”),一个有空格,一个没有空格就出错了。
这个违背了equals的自反性原则:对于任何非空引用x,x.equals(x)应该返回true。
这里只要去掉trim方法就可以解决。
2、对称性原则
上面这个例子,还并不是很好,如果我们传入null值,会怎么样呢?增加一条语句:Person p2=new Person(null);
结果:
|
1
2
|
是否包含张三:trueException in thread "main" java.lang.NullPointerException |
原因在执行p2.equals(p1)时,由于p2的name是一个null值,所以调用name.equalsIgnoreCase()方法时就会报空指针异常。
这是在覆写equals方法时没有遵循对称性原则:对于任何应用x,y的情形,如果想x.equals(y)返回true,那么y.equals(x),也应该返回true。
应该在equals方法里加上是否为null值的判断:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
@Override public boolean equals(Object obj) { if (obj instanceof Person) { Person person= (Person) obj; if (person.getName() == null || name == null) { return false; }else{ return name.equalsIgnoreCase(person.getName()); } } return false; } |
3、传递性原则
现在我们有一个Employee类继承自person类:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public class Employee extends Person{ private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } public Employee(String name,int id) { super(name); this.id = id; // TODO Auto-generated constructor stub } @Override public boolean equals(Object obj) { if(obj instanceof Employee){ Employee e = (Employee)obj; return super.equals(obj) && e.getId() == id; } return super.equals(obj); } public static void main(String[] args){ Employee e1=new Employee("张三",12); Employee e2=new Employee("张三",123); Person p1 = new Person("张三"); System.out.println(p1.equals(e1)); System.out.println(p1.equals(e2)); System.out.println(e1.equals(e2)); }} |
只有在name和ID都相同的情况下才是同一个员工,避免同名同姓的。在main里定义了,两个员工和一个社会闲杂人员,虽然同名同姓但肯定不是同一个人。运行结果应该三个都是false才对。但是:
true
true
false
p1尽然等于e1,也等于e2,不是同一个类的实例也相等了?因为p1.equals(e1)是调用父类的equals方法进行判断的它使用instanceof关键字检查e1是否是person的实例,由于employee和person是继承关系,结果就是true了。但是放过来就不成立,e1,e2就不等于p1,这也是违反对称性原则的一个典型案例。
e1竟然不等于e2?e1.equals(e2)调用的是Employee的equals方法,不仅要判断姓名相同还有判断工号相同,两者的工号不同,不相等时对的。但是p1等于e1,也等于e2,e1却不等于e2,这里就存在矛盾,等式不传递是因为违反了equals的传递性原则:对于实例对象x、y、z;如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。
上述情况会发生是因为父类使用instanceof关键字(是否是这个特定类或者是它的子类的一个实例),用来判断是否是一个类的实例对象的,这很容易让子类“钻空子”。想要解决也很简单,使用getClass进行类型的判断,person类的equals方法修改如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
@Override public boolean equals(Object obj) { if (obj != null && obj.getClass() == this.getClass()) { Person person= (Person) obj; if (person.getName() == null || name == null) { return false; }else{ return name.equalsIgnoreCase(person.getName()); } } return false; } |
4、必须覆写hashCode方法这样结果就是三个false。
覆写equals方法就必须覆写hashCode方法,这是Javaer都知道的。原因就是HashMap的底层处理机制是以数组的方式保存map条目的,这其中的关键是这个数组下标的处理机制:依据传入元素的hashCode方法的返回值决定其数组的下标,如果该数组位置上已经有了map条目,且与传入的键值相等则不处理,若不相等则覆盖;如果数组位置没有条目,则插入,并加入到map条目的链表中。同理检查键是否存在也是根据哈希吗确定文职,然后遍历查找键值的。
那么对象的hashCode方法返回的是什么呢?他是一个对象的哈希码,是有Object类的本地方法生成的,确保每个对象有一个哈希码。
java重写equals方法的更多相关文章
- java重写equals方法需要注意的几点
为什么equals()方法要重写? 判断两个对象在逻辑上是否相等,如根据类的成员变量来判断两个类的实例是否相等,而继承Object中的equals方法只能判断两个引用变量是否是同一个对象.这样我们往往 ...
- Java重写equals方法(重点讲解)
为什么equals()方法要重写? 判断两个对象在逻辑上是否相等,如根据类的成员变量来判断两个类的实例是否相等,而继承Object中的equals方法只能判断两个引用变量是否是同一个对象.这样我们往往 ...
- Effective Java 第三版——10. 重写equals方法时遵守通用约定
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——11. 重写equals方法时同时也要重写hashcode方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- JAVA中重写equals()方法的同时要重写hashcode()方法
object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true:注意:当此方法 ...
- JAVA中重写equals()方法为什么要重写hashcode()方法?
object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true:注意:当此方法 ...
- Java中equals和==的区别?为什么重写equals方法后,一定要重写hashCode方法?
首先明确一点,equals是方法,==是操作符. 1. 如果比较的是基本数据类型: 只讨论==,因为equals是不存在的,因为java中基本数据类型不能调用method的. 2. 如果比较的是引用类 ...
- java重写equals和hashCode方法
一.重写equals方法 如果不重写equals,那么比较的将是对象的引用是否指向同一块内存地址,重写之后目的是为了比较两个对象的value值是否相等. 利用equals比较八大包装对象(如int,f ...
- 一文搞懂--Java中重写equals方法为什么要重写hashcode方法?
Java中重写equals方法为什么要重写hashcode方法? 直接看下面的例子: 首先我们只重写equals()方法 public class Test { public static void ...
随机推荐
- Java 基础【07】线程同步锁的选择
在需要线程同步的时候如何选择合适的线程锁? 例:选择可以存入到常量池当中的对象,String对象等 public class SyncTest { private String name = &quo ...
- GitHub: Windows 下的简单使用
这段时间在博客园多了很多关于GitHub的文章,但是我的确没怎么看懂.不过这几天简单的看了写资料,亲身操作之后也有了一点体会.这算是最简单的GitHub入门了吧,基本全是鼠标操作.这也是这几天的总结, ...
- Python3.5 + django1.8.5 安装”import pymysql pymysql.install_as_MySQLdb()”的解决方法
最近在学习Python,打算先看两个在线教程,再在github上找几个开源的项目练习一下,在学到"被解放的姜戈"时遇到django同步数据库时无法执行的错误,记录一下. 错误现象: ...
- HDU5878~HDU5891 2016网络赛青岛
A.题意:给出一个整数n, 找出一个大于等于n的最小整数m, 使得m的质因数只有2 3 5 7 分析:预处理出质因数2 3 5 7的数,超过maxt就行,然后找 B.题意:求1/1^2+1/2^2+. ...
- linux 权限
ls -la 查看文件 drwxr-xr-x 2 root root 4096 ...... 第一个d:代表目录:-代表文件 后面三个一组:r:读:w:写:x:执行 第一个root 代表所属用户: 第 ...
- morris的用法
參數選項說明: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ...
- Beta版本冲刺———第二天
会议照片: 项目燃尽图: 1.项目进展: 昨天的困难:分数排行榜的设计 今天解决的进度:完成了界面优化以及建立新的排行榜选项卡界面. 明天要做的事情:分数排行榜的功能设计 2.每个人每天做的事情 郭怡 ...
- Hibernate用注解实现实体类和表的映射
数据库mysql: 1.一对一 person50表password50表是一对一的关系: password50表中有外键 person_id person实体类: package com.c50.en ...
- MySQL的恢复脚本
原文转自: http://blog.csdn.net/dbanote/article/details/13295727 应用场景: ********************************** ...
- 天朝git的使用
开源中国社区 官方网站 https://git.oschina.net/ 开源中国社区成立于2008年8月,其目的是为中国的IT技术人员提供一个全面的.快捷更新的用来检索开源软件以及交流使用开源经验的 ...