网站首页 > java教程 正文
1. equals 和 hashCode 方法之间的关系
这两个方法都是 Object 的方法,意味着 若一个对象在没有重写 这两个方法时,都会默认采用 Object 类中的方法实现,它们的关系为:
- 如果两个对象通过equals()方法比较相等,那么这两个对象的hashCode一定相同。
- 如果两个对象hashCode相同,不能证明两个对象是同一个对象(不一定相等),只能证明两个对象在散列结构中存储在同一个地址(不同对象hashCode相同的情况称为hash冲突)。
2.为什么重写equals 后需要重写 hashCode
Effective Java 第三版 中 描述为什么重写equals 方法后必须重写hashCode 方法:
每个覆盖了equals方法的类中,必须覆盖hashCode。如果不这么做,就违背了hashCode的通用约定,也就是上面注释中所说的。
进而导致该类无法结合所以与散列的集合一起正常运作,这里指的是HashMap、HashSet、HashTable、ConcurrentHashMap。
上面注释 为 Object 类中 hashCode 方法注释:
If two objects are equal according to the {@code equals(Object)}
* method, then calling the {@code hashCode} method on each of
* the two objects must produce the same integer result.
结论:如果重写equals不重写hashCode它与散列集合无法正常工作。
3. 以 HashMap 为例进行论证分析
查看 hashMap 的 put 方法
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
查看hash 方法的实现:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
查看 get 方法的实现:
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
java中HashMap的数据结构是数组+链表+红黑树;这种数据结构,每个键值对都会被存在相应的地址中,从代码中可以看出HashMap是通过key的hashCode以及自身的容量来决定当前键值的存储索引(桶)的,确定桶的位置后,再进入桶中同时判断hashCode和equals两个方法。那也就是说,如果hashCode不同,那么HashMap就一定会创建一个新的Node键值对象。
HashMap在put一个键值对时,会先根据键的hashCode和equals方法来同时判断该键在容器中是否已经存在,如果存在则覆盖,反之新建。所以如果我们在重写equals方法时,没有重写hashCode方法,那么hashCode方法还是会默认使用Object提供的原始方法,而Object提供的hashCode方法返回值是不会重复的(也就是说每个对象返回的值都不一样)。所以就会导致每个对象在HashMap中都会是一个新的键。
反向论证:若一个类中重写了 equals 方法,没有重写hashCode方法;且该类的两个对象具有不同属性但 hashCode 相等,在hashMap 以该对象为键进行存储时,会出现hash冲突现象,但发现该类重写了equals 方法,且通过该类的equals 比较之后也是相等,就会出现 hashMap 中只保存了一个对象,采用get 方法获取时,就会获取到别的对象,从而导致获取对象错乱。
因此 重写equals 方法必须重写 hashCode 方法,用来保证两个对象通过equals()方法比较相等,那么这两个对象的hashCode一定相同 这一原则;
文章来自https://www.cnblogs.com/zjdxr-up/p/16177068.html
猜你喜欢
- 2025-01-02 Netty 断开重连
- 2025-01-02 “算法考核没过,老板找我聊了3个小时”:离职程序员重刷数学题
- 2025-01-02 List 去除重复数据的五种方式,舒服
- 2025-01-02 你真的会用MySQL去重吗?看看DISTINCT和GROUP BY的奥秘
- 2025-01-02 Java8两个List集合取交集、并集、差集、去重并集
- 2025-01-02 干货实战~Java如何防止接口重复提交
- 2025-01-02 面试突击63:MySQL 中如何去重?
- 2025-01-02 Java中List集合对象去重及按属性去重的8种方法
- 2025-01-02 Java实现10万+并发去重,持续优化
- 2025-01-02 java接口防重提交如何处理
你 发表评论:
欢迎- 04-24Java Collections 工具类集合框架中常用算法解析
- 04-24桶排序的简单理解
- 04-24Java集合框架底层实现原理大揭秘
- 04-24Java 集合框架全面解析:选对数据结构,提升开发效率
- 04-24c#集合排序
- 04-24Java面试中常被问到的集合类深度解读
- 04-24VBA技术资料MF278:对集合进行排序
- 04-24Spring 最常用的 7 大类注解,史上最强整理
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)