- 浏览: 1667109 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (335)
- uml (11)
- java (318)
- python (11)
- socket (2)
- ant (1)
- data structures (58)
- algorithms (67)
- concurrency (16)
- multithreading (16)
- mysql (2)
- ubuntu (2)
- c语言 (1)
- lucene (0)
- elasticsearch (0)
- django (1)
- 读书 观点 (2)
- 读书 (4)
- 观点 (4)
- collections (8)
- nio (1)
- io (2)
- 系统集成 (1)
- activemq (2)
- restful (0)
- web service (0)
- HttpClient (1)
- serializable (0)
- annotation (1)
- jdbc (3)
- classloader (0)
- regular expression (1)
- jpa (4)
- jvm (0)
- reflection (1)
- commons-pool2 (2)
- javamail (1)
- velocity (1)
- mathematics (3)
- graph (13)
- LeetCode (159)
- scala (0)
- spring (24)
- maven (5)
- spring batch (1)
- quartz (2)
- IOC (2)
- ORM (3)
- hibernate (2)
- aop (4)
- redis (0)
- zookeeper (0)
- spring mvc (4)
- ELK (1)
- string (1)
- gradle (1)
- mybatis (5)
- docker (0)
- servlet (0)
- log4j2 (1)
- html (0)
- css (0)
最新评论
-
nucleus:
貌似是因为图片的路径是http的缘故:http://dl2.i ...
spring container 实现分析:BeanWrapper -
nucleus:
nucleus 写道BeanWrapper这一块相关的类结构如 ...
spring container 实现分析:BeanWrapper -
nucleus:
BeanWrapper这一块相关的类结构如下图:文中提到的上述 ...
spring container 实现分析:BeanWrapper -
leshy:
inventory.sort(Comparator.compa ...
java8 lambda表达式学习总结 -
Leisurez:
di1984HIT 写道xuexile~hahaha~
activemq的几种基本通信方式总结
equals方法
书上说,我们要比较两个对象是否相等的时候需要定义equals()和hashCode()两个方法。equals方法的完整签名是:equals(Object o). 定义equals方法的过程无非以下几个步骤:
1. 比较传进来的对象是否为空,如果空则返回false。
2. 比较传进来的对象类型是否相同,不同则返回false.
3. 再根据定义的对象比较每个字段是否相等,不等则返回false.
我们都知道,equals()方法意味着一种可传递和交换的对等关系,也就是说,假如A.equals(B)的结果为true的话,那么B.equals(A)的结果也是true.
如果引入了类继承关系的时候,子类需要定义同样的方法时可以重用父类的方法,只针对自己的部分进行修改。但是在稍微不注意的情况下可能会打破前面的这种假定。
继承关系的一个实现
在不考虑hashCode方法的情况下,下面是一个包含父类和子类的equals实现:
class BaseClass { private int x; public BaseClass(int i) { x = i; } public boolean equals(Object rhs) { if(!(rhs instanceof rhs)) return false; return x == ((BaseClass)rhs).x; } } class DerivedClass extends BaseClass { private int y; public DerivedClass(int i, int j) { super(i); y = j; } public boolean equals(Object rhs) { if(!(rhs instanceof DerivedClass)) return false; return super.equals(rhs) && y == ((DerivedClass)rhs).y; } } public class EqualsWithInheritance { public static void main(String[] args) { BaseClass a = new BaseClass(5); DerivedClass b = new DerivedClass(5, 8); DerivedClass c = new DerivedClass(5, 8); System.out.println("b.equals(c): " + b.equals(c)); System.out.println("a.equals(b): " + a.equals(b)); System.out.println("b.equals(a): " + b.equals(a)); } }
如果我们运行上面的代码,会发现一个比较奇怪的结果:
b.equals(c): true a.equals(b): true b.equals(a): false
既然我们前面a.equals(b)为true了,为什么后面b.equals(a)的结果反而成为了false呢?这样的实现肯定有问题,很明显,它打破了equals()的对等性。
问题分析
如果我们仔细去看前面的代码实现的话,会发现问题很可能出现在父类和子类定义的equals()方法中。在父类中定义的equals方法子类中也定义了。所以当我们a.equals(b)调用的时候,因为a是父类创建的对象,所以执行的是父类里的equals方法,而b是子类的实例化对象,b.equals(a)执行的是子类中的equals方法。
另外,还有一个问题就是instanceof。在java里面,instanceof表示测试它左边的对象是否为它右边类的实例。由于类的继承关系,我们可以说一个子类也是父类的实例。比如说,在java中,所有对象都是继承自Object,那么我们任意定义的一个类的实例对象调用instanceof Object返回的结果都为true.所以问题的根源就在于这个instanceof。
再看我们的这个问题,我们本身的逻辑要求是父类的实例和子类的实例是不一样的,所以a.equals(b)和b.equals(a)都应该返回false.那么,现在问题就是,我们该用什么方法来比较父类和子类是不同的类型呢?查阅过文档之后,我们可以使用getClass()方法。这个方法表示返回该对象的运行时class。我们都知道,在jvm虚拟机中,每个类的详细类型信息会被定义在方法区中,并被多个线程所共享。这里将包括每个类的详细不同,比如说b是类DerivedClass实例化的对象,这样就可以实现他们的区分。
下面是修改后的实现代码:
class BaseClass { private int x; public BaseClass(int i) { x = i; } public boolean equals(Object rhs) { if(rhs == null || getClass() != rhs.getClass()) return false; return x == ((BaseClass)rhs).x; } } class DerivedClass extends BaseClass { private int y; public DerivedClass(int i, int j) { super(i); y = j; } public boolean equals(Object rhs) { return super.equals(rhs) && y == ((DerivedClass)rhs).y; } } public class EqualsWithInheritance { public static void main(String[] args) { BaseClass a = new BaseClass(5); DerivedClass b = new DerivedClass(5, 8); DerivedClass c = new DerivedClass(5, 8); System.out.println("b.equals(c): " + b.equals(c)); System.out.println("a.equals(b): " + a.equals(b)); System.out.println("b.equals(a): " + b.equals(a)); } }
运行结果如下:
b.equals(c): true a.equals(b): false b.equals(a): false
总结:
对象的equals()方法在结合继承的关系时容易被搞混淆。重点就是根据我们逻辑定义,如果需要详细考虑父类和子类的差别的话,应该考虑object.getClass()而不是instanceof。
参考资料
Inside the java 2 virtual machine
Data structures & problem solving Using java
评论
1. 比较传进来的对象是否为空,如果空则返回false。
2. 比较传进来的对象类型是否相同,不同则返回false.
3. 再根据定义的对象比较每个字段是否相等,不等则返回false.
第三点的说法不准确.未必会比较每个字段,这是自定义的.
是的,因为是自己来定义,可以选择对于对象比较有意义的字段。
+1 equals 方法和hashcode实际上是为业务逻辑规定的对比方法,没必要死磕每个字段,你完全可以自定义任意规则!!
1. 比较传进来的对象是否为空,如果空则返回false。
2. 比较传进来的对象类型是否相同,不同则返回false.
3. 再根据定义的对象比较每个字段是否相等,不等则返回false.
第三点的说法不准确.未必会比较每个字段,这是自定义的.
是的,因为是自己来定义,可以选择对于对象比较有意义的字段。
1. 比较传进来的对象是否为空,如果空则返回false。
2. 比较传进来的对象类型是否相同,不同则返回false.
3. 再根据定义的对象比较每个字段是否相等,不等则返回false.
第三点的说法不准确.未必会比较每个字段,这是自定义的.
发表评论
-
spring源代码分析:aop的实现
2018-10-03 23:32 688简介 在之前的文章里我们讨论过一些程序构建Pro ... -
java annotation基础
2018-06-30 16:41 833简介 之前有一篇简短的文章讨论过annotati ... -
spring源代码分析:annotation支持的实现
2018-09-03 23:31 2461简介 在之前的文章里,我们讨论了spring I ... -
spring container 实现分析:BeanFactory and ApplicationContext
2018-06-02 18:29 1406简介 在之前的文章里,我们讨论过作为spring ... -
spring aop: ProxyFactory
2018-04-30 16:45 790简介 在之前的文 ... -
日志与log4j2的配置和应用总结
2018-02-15 15:47 12197简介 通常我们在日常的应用开发中,日志起到一个非 ... -
Java servlet学习总结
2018-01-02 21:14 0简介 应用系统架构的演化(从CS到BS) ... -
spring container 实现分析:BeanWrapper
2018-02-19 18:10 1856简介 在之前的一篇文章里, 我们基于《Exper ... -
spring propertyeditor
2017-10-26 09:17 0pro spring 5 chapter 4, page ... -
spring bean life cycle
2018-02-25 13:30 872简介 在使用spring bean的过程中,有一个 ... -
spring container的设计与实现分析
2017-10-08 21:31 2657简介 在之前的一 ... -
jdbc数据访问的封装和演化
2017-09-16 17:00 2602简介 在使用传统jdbc的方式来访问数据的时候, ... -
Boyer Moore算法分析总结
2017-03-31 18:42 3483简介 在之前的文章里,对于字符串的搜索算法,我曾 ... -
mybatis学习总结:mybatis和spring, spring boot的集成
2017-03-04 18:07 2468简介 在前面的讨论里已经提到了mybatis的各种配置 ... -
mybatis学习总结:annotation与xml结合示例
2017-02-25 21:09 3650简介 在之前的文章里讨论过mybatis纯xml或者 ... -
mybatis学习总结:对象关系映射的xml配置实现
2017-02-19 23:03 4011简介 在之前的文章里已经讨论过mybatis的基本配 ... -
mybatis学习总结:annotation示例改进
2017-01-24 09:06 3386简介 在前一篇文 ... -
mybatis学习总结:基础示例
2017-01-21 23:30 844简介 mybatis是一个比较流行的ORM框架, ... -
gradle学习总结
2016-12-18 21:01 4531简介 Java的自动化构建工具比较多,从最开始的an ... -
String sort的几种方法
2016-10-16 23:07 2120简介 在之前的一 ...
相关推荐
equals()和hashcode()这两个方法都是从object类中继承过来的。当String 、Math、还有Integer、Double。。。。等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法.
equals方法重写作业,Students类,有三个属性id ,name ,grade。还有一个测试类用于测试创建了三个对象前两各对象的数据完全一样,第三个对象的数据不同。使用equals方法比较。并输出结果。
重载equals方法示例重载equals方法示例重载equals方法示例重载equals方法示例重载equals方法示例
Java中的==与equals()实例方法Java中测试两个变量是否相等的方法有两个,一个是用==运算符,另一个就是object类提供的equals()方法。2
本文档详细介绍了set接口为什么会用到hashCode和equals方法以及这两个方法的一些探讨 set不同的实现类用到的这两个方法也不同
Java中equals方法隐藏的陷阱
本文讲述了什么时候重写equals方法和如何重写equals方法。
写一个类Student,包含三个属性学号id,姓名name和年龄age;要求覆盖基类Object中的ToString()方法和Equals()方法,使得直接输出Student对象时输出的是对象的id,name和age信息;并且当两个对象的学号相同时认为它们...
hashCode()和equals()定义在Object类中,这个类是所有java类的基类,所以所有的java类都继承这两个方法。 使用hashCode()和equals() hashCode()方法被用来获取给定对象的整数。这个整数被用来确定对象被...
本文介绍了Java语言不直接支持关联数组,可以使用任何对象作为一个索引的数组,但在根Object类中使用 hashCode()方法明确表示期望广泛使用HashMap。理想情况下基于散列的容器提供有效插入和有效检索;直接在对象模式...
重写toString和equals方法的意义以及方法
变量obj是一个内存,new Object()是另一个内存,此时,变量obj所对应的内存中存储的数值就是对象占用的那块内存的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的...
js equals 比较两个对象是否相等
知识点 比较运算符==和equals方法的比较 知识点 比较运算符==和equals方法的比较
这里是一个文档,里边讲解了hashCode与equals方法使用,大家要是不明白,可以去看看
2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2.javaequals()方法.zip2....
更清楚的了解hashcode()和equals()方法。
C# Equals 和 GetHashCode 方法重写,
设计一个名为MyInteger的类,类包含: 一个名为valuede 的int型数据域,保存次对象表示的int型值 一个用指定的int型值创建一个MyInteger对象的构造函数 一个返回int型值的获取器函数 函数isEven()、isOdd()和isPrime...
Object类中的equals 方法,两个对象为同一个时返回true,如果不是同一个返回false。 通常,equals方法用于比较两个对象的内容是否一样,这时就需要类去覆盖Object的equals()方法,在equal()方法内自定义相等的规则。...