- 浏览: 802569 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (360)
- Java (101)
- JPA/Hibernate (10)
- Spring (14)
- Flex/BlazeDS (37)
- Database (30)
- Lucene/Solr/Nutch (0)
- Maven/Ant (25)
- CXF/WebService (3)
- RPC/RMI/SOAP/WSDL (1)
- REST (6)
- TDD/BDD/JUnit (1)
- Servlet/JSP (2)
- AI/MachineLearning (3)
- Resource (1)
- 字符编码 (2)
- OOA/OOPS/UML (5)
- DesignPattern (8)
- 算法与数据结构 (11)
- Web&App Server (13)
- 并发&异步&无阻塞 (7)
- Entertainment (4)
- JavaScript/ExtJS (45)
- CodeStyle&Quality (1)
- svn/git/perforce (8)
- JSON (2)
- JavaScriptTesting (4)
- Others (6)
- RegularExpression (2)
- Linux/Windows (12)
- Protocal (2)
- Celebrities (1)
- Interview (1)
- 计算机语言 (1)
- English (2)
- Eclipse (5)
- TimeZone/时区 (1)
- Finance (1)
- 信息安全 (1)
- JMS/MQ (2)
- XSD/XML/DTD (3)
- Android (4)
- 投资 (3)
- Distribution (3)
- Excel (1)
最新评论
-
qdujunjie:
如果把m换成具体的数字,比如4或者5,会让读者更明白
m阶B树中“阶”的含义 -
java-admin:
不错,加油,多写点文章
关于Extjs的mixins和plugin -
xiehuaidong880827:
你好,我用sencha cmd打包完本地工程后,把app.js ...
ExtJS使用Sencha Cmd合并javascript文件为一个文件 -
KIWIFLY:
lwpan 写道inverse = "true&qu ...
Hibernate中什么时候使用inverse=true -
luedipiaofeng:
good
消除IE stop running this script弹出框
两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
不对
两个对象有相同的hash code,但是值不同(x.equals(y) == false),这句话对不对?
对,hash code相同,说明value在同一个bucket里面,也可以说是hash冲突,x.equals(y)为true说明x和y是同一个业务对象,x.equals(y)为false说明不是同一个业务对象,产生了hash冲突。所以如果x.equals(y)==false,程序员应该知道,给不相同的x和y对象产生截然不同的hash code,有可能提高散列表(hash table)的性能。
因为如果只覆盖了equals而没有覆盖hashCode, 则两个不同的instance a和b虽然equals结果(业务逻辑上)相等,但却会有不同的hashcode,这样hashmap里面会同时存在a和b,而实际上我们需要hashmap里面只能保存其中一个,因为从业务逻辑方向看它们是相等的.
为了能让集合框架中的类如HashMap正常工作,必须保证同时覆盖equals()和hashCode(),而且注意不要由于写错了参数类型,而重载了这两个方法,却并没有覆盖它们,比如:
public boolean equals(Object obj) 写成了public boolean equals(ClassXXX obj) 。
为什么在覆盖equals时一定也要覆盖hashCode呢? 下面用HashMap来阐述原因,首先假设key1和key2的值在业务逻辑领域是相等的,即它们应该是同一个对象,HashMap已经存储了key1,现在要查找key2是否存在,正确的结果应该是存在:
Java中的HashMap实际上是一个链表数组,即首先HashMap是一个数组,然后数组中的每一个元素是一个链表(更通用的概念可以称为桶bucket,Java中的HashMap用Entry类描述链表的结点结构),HashMap在执行Put,Contains之类的操作时,会首先根据你提供的Key计算hashCode值,然后根据这个hashCode值在数组中找到某一个链表或桶(通常是找到链表的起始结点),这一步操作利用了hashCode()方法,如果你覆盖了就会用你提供的方法,在找到某一个链表的起始结点后,就会遍历链表,然后通过equals方法来寻找是否存在与Key的值相等的结点,如果执行equals方法后的结果相等,HashMap就认为已经存在这个元素,这一步如果你覆盖了equals方法就会用到你提供的equals方法。
通过上面的描述,我们发现equals方法和hashCode方法如果不同时按你自己逻辑覆盖的话,HashMap就会出问题。比如你只覆盖了equals方法而没有覆盖hashCode方法,那么HashMap在第一步寻找链表的时候会出错,有同样值的两个对象Key1和Key2并不会指向同一个链表或桶,因为你没有提供自己的hashCode方法,那么就会使用Object的hashCode方法,该方法是根据内存地址来比较两个对象是否一致,由于Key1和Key2有不桶的内存地址,所以会指向不同的链表,这样HashMap会认为key2不存在,虽然我们期望Key1和Key2是同一个对象;反之如果只覆盖了hashCode方法而没有覆盖equals方法,那么虽然第一步操作会使Key1和Key2找到同一个链表,但是由于equals没有覆盖,那么在遍历链表的元素时,key1.equals(key2)也会失败(事实上Object的equals方法也是比较内存地址),从而HashMap认为不存在Key2对象,这同样也是不正确的。
以下内容摘自<<Effective Java>>
覆盖equals时总要覆盖hashCode,一个很常见的错误根源在没有覆盖hashCode方法。在每个覆盖了equals方法的类中,也必须覆盖hashCode方法。如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常工作,这样的集合包括HashMap、HashSet和Hashtable。
下面是约定的内容,摘自Object规范[JavaSE6]:
1)在应用程序的执行期间,只要对象的equals方法所用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法都必须始终如一地返回同一个整数。在同一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。
2)如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。
3)如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中的任意一个对象的hashCode方法,则不一定要产生不同的整数结果。但是程序员应该知道,给不相同的对象产生截然不同的整数结果,有可能提高散列表(hash table)的性能。
如果覆盖equals没有覆盖hashCode,将会违反上面的第2条:相等的对象必须具有相等的散列码(hashCode)。Object类里面的默认eqals方法是比较内存地址是否相等,默认的hashCode方法则是根据内存地址产生一个整数,所以Object类本身当然是符合上面规则的。当你覆盖了equals后,内存地址不同的对象可能会相等,而如果这时你没有覆盖hashCode方法的话,hashCode还是根据内存地址来生成,就会出现相等的对象具有不同的散列码的情况。
下面给出了一个重载equals和hashCode的样本:
package core; public class OverrideEqualsAndHashCodeSample { private String name; private String region; private String position; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRegion() { return region; } public void setRegion(String region) { this.region = region; } public String getPosition() { return position; } public void setPosition(String position) { this.position = position; } @Override public boolean equals(Object o) { if(o==null) return false; if(!(o instanceof OverrideEqualsAndHashCodeSample)) return false; if(this==o) return true; OverrideEqualsAndHashCodeSample o2=(OverrideEqualsAndHashCodeSample)o; if(name.equalsIgnoreCase(o2.name) && region.equalsIgnoreCase(o2.region) && position.equalsIgnoreCase(o2.position)) return true; return false; } @Override public int hashCode() { int result=17; result=31*result+name!=null?name.hashCode():0; result=31*result+region!=null?region.hashCode():0; result=31*result+position!=null?position.hashCode():0; return result; } }
摘自http://www.importnew.com/22083.html 第16个问题
为什么通常选择31这个数?
选择31是因为可以用移位和减法运算来代替乘法,从而得到更好的性能。说到这里你可能已经想到了:31 * num 等价于(num << 5) – num,左移5位相当于乘以2的5次方再减去自身就相当于乘以31,现在的VM都能自动完成这个优化。
关于HashCode和Equals的文章:
详解 equals() 方法和 hashCode() 方法
http://www.importnew.com/29154.html
发表评论
-
sapjco3 notes
2019-03-21 14:51 1160sapjco https://support.sap.com/ ... -
使用RestTemplate发送post JSON请求
2019-01-12 17:30 4725private final String BASE_URL = ... -
使用RestTemplate发送post JSON请求
2019-01-12 17:30 3495private final String BASE_URL = ... -
Spring线程池ThreadPoolTaskExecutor
2018-08-06 09:51 1878<!-- spring thread pool ex ... -
Spring注解事物@Transactional不工作
2018-08-02 18:50 2668“In proxy mode (which is the de ... -
创建前缀索引报长度超出错误
2018-07-25 15:44 1723表结构定义如下: CREATE TABLE `sku` ( ` ... -
Mysql Varchar字符长度
2018-07-25 15:23 1349`sku_name` VARCHAR(200) NOT NUL ... -
使用 Spring RestTemplate 发送 post 请求
2018-07-23 18:49 11719注意点: 1)使用MultiValueMap设置入参,不要使 ... -
Java动态代理Dynamic Proxy
2018-07-21 16:33 806JAVA学习篇--静态代理VS动态代理 https://blo ... -
分布式实时日志分析解决方案 ELK 部署架构
2018-07-20 09:52 1186原文链接:http://www.importn ... -
为什么HashMap容量一定要为2的幂呢?
2018-07-19 10:07 1725原文链接:https://blog.csdn.net/wang ... -
为什么计算HashCode时通常选择31这个数?
2018-07-19 10:05 1415摘自http://www.importnew.com/2208 ... -
jackson自定义序列化和反序列化
2018-07-10 18:47 2238原文链接:https://blog.csdn.net/liu ... -
Pay special attention when modifying online running system
2017-06-23 10:25 0Never remove any properties, me ... -
Map中的Null key, Null Value
2017-06-14 10:52 1940ConcurrentHashMap的key和value都不能为 ... -
Java语法糖
2017-06-05 20:03 526Java语法糖之foreach http://www.imp ... -
排序算法
2017-05-30 13:07 507各种排序算法的分析及java实现 http://www.cnb ... -
Java集合相关
2017-05-24 17:55 0Java集合框架:ArrayList http://www. ... -
区块链,以太坊,blockchain,ethereum
2017-05-19 14:35 885摘自:http://36kr.com/p/5075127.h ... -
Java数据类型的转换:隐式(自动)转换与强制转换
2017-05-14 10:46 0http://blog.csdn.net/u011240877 ...
相关推荐
例如,public boolean equals(Object o) 是一个正确的重写方法,而 public boolean equals(String o) 是一个重载方法,而不是重写方法。 equals 方法的实现 ------------------------- equals 方法的实现需要遵循...
Java编程中避免equals方法的隐藏陷阱介绍 Java编程中避免equals方法的隐藏陷阱介绍是一篇重要的技术文章,主要介绍了Java编程中避免equals...避免equals方法的隐藏陷阱需要我们小心地重载equals方法,避免常见的陷阱。
- **为什么同时覆盖equals和hashCode?** - 当两个对象根据equals方法比较相等时,它们的hashCode值也必须相同,这是为了确保基于哈希的集合能够正确地工作。 - **hashCode的作用**: - 主要是为了配合基于散列的...
2.如果要重写一个对象的 equals 方法,还需要重写该对象的 hashCode 方法,以确保对象的哈希码正确。 六、Java 中的继承和多态 1. Java 中的继承是一种实现代码重用的机制,子类可以继承父类的属性和方法。 2. ...
- **equals方法的重载**:当类需要实现逻辑等价测试时,应重载equals方法,确保与hashCode方法一起使用。如果类的实例是唯一的或者不需要逻辑等价性,则不必重载。 - **hashCode方法的重载**:与equals方法一起...
3. hashCode 和 equals 方法的相关规定:当 equals 方法被覆盖时,hashCode 方法也必须被覆盖。 IO 流知识点: 1. BIO、NIO、AIO:BIO 是阻塞式 IO,NIO 是非阻塞式 IO,AIO 是异步 IO。 2. Files 的常用方法:...
这是因为equals方法和hashCode方法是两个独立的方法,equals方法用于比较两个对象的值是否相等,而hashCode方法用于生成对象的哈希码。 5. 不可以继承String类,因为String类是final类,不能被继承。 6. 当一个...
本节课主要讲解Java基础知识,包括跨平台性、逻辑运算符、构造器、break、continue、return语句、equals和hashCode方法、String类继承、值传递和引用传递等内容。 1. 跨平台性 Java语言编写的程序,一次编译后,...
Object类提供了一些常用的方法,如equals()、hashCode()、toString()等。 本节课件还讲解了super、this、final关键字的使用方法。super关键字用于访问父类的成员变量和方法,而this关键字用于访问当前对象的成员...
但是hashCode相等时,equals不一定相等。在使用集合框架存储对象时,如果重写了equals方法,也应该重写hashCode方法,以保证对象的一致性。 9. 抽象类和接口的区别: - 语法层次:抽象类可以用abstract关键字定义,...
9. **equals()与hashCode()与多态**:Object类中的equals()和hashCode()方法默认比较的是对象的引用。当自定义类时,通常需要重写这两个方法以实现基于对象属性的比较,这也是多态的一种体现。 10. **多态与异常...
- 覆写equals方法时要处理null值,同时覆写hashcode以保持一致性。 - 推荐覆写toString方法,提供更友好的输出。 - 使用package-info.java为包提供元数据。 4. **字符串操作**: - 使用字符串直接量赋值,提高...
最后,JAVA还提供了几种特殊的方法,如构造器(用于初始化对象),`equals()`和`hashCode()`(用于比较对象的平等性),以及`toString()`(用于返回对象的字符串表示)。 综上所述,JAVA语言程序设计中的第四章方法...
重写(Overriding)发生在子类对父类方法的覆盖,要求子类方法与父类方法有相同的名称、参数列表,并且访问修饰符不能小于父类,返回值必须一致或为父类返回值的子类类型,抛出的异常不能比父类方法更大。...
散列码用于确定对象在散列表中的索引位置,建议覆盖equals方法时也覆盖hashCode方法。 8. String类不可继承:String类在Java中被声明为final,因此不能被继承。 9. 方法的值传递和引用传递:在Java中,传递参数到...
7. equals 方法和 hashCode 方法:如果重写了 equals 方法,就一定要重写 hashCode 方法,因为两个对象相等那么 hashCode 值也得相同。 8. 类的初始化顺序:类的初始化顺序是父类静态成员变量、父类静态代码块、...
32. 为什么要有 hashCode? hashCode用于对象的快速比较和存储。 二十八、包装类型和自动装箱 43. 包装类型是什么?基本类型和包装类型有什么区别? 包装类型是基本类型的对象形式,基本类型是原始类型,包装类型...