java--map容器的hashcode和equals
先看一个例子
首先定义一个user类。
package com.text.tool; public class User {
int id; User(int id) {
this.id = id;
} public String toString() {
return "key="+id;
}
}
其次写一个测试类,创建一个HashMap,在map中User对象作为KEY。
package com.text.tool; import java.util.HashMap;
import java.util.Map; public class TestMap { public static void main(String[] args) {
Map map = new HashMap();
map.put(new User(1), 1);
map.put(new User(2), 1);
map.put(new User(3), 1); System.out.println(map.keySet());
System.out.println(map.get(new User(1))
}
}
输出结果,让人疑惑的是为什么MAP数组中匹配不到new User(1)。
[key=1, key=2, key=3]
null
我们可以简单看下HashMap源码,在源码中获取到key对应value做了一个判断,e.hash == hash && eq(k, e.key)也就是对key的hashcode进行比对,以及进行equals判断。
我们传入的对象User默认继承Object,所以equals及hashCode默认是Object的方法,而此时这里的equals比较的是两个对象的内存中的地址并非value,所以第二个new User(1)就无法再MAP数组中取到value了。
public Object get(Object key) {
Object k = maskNull(key);
int hash = hash(k);
int i = indexFor(hash, table.length);
Entry e = table[i];
while (true) {
if (e == null)
return e;
if (e.hash == hash && eq(k, e.key))
return e.value;
e = e.next;
}
}
public boolean equals(Object obj) {
return (this == obj);
}
public native int hashCode();
在User类中重写equals及hashcode方法,在启用main方法就不会有问题了。
package com.text.tool; public class User {
int id; User(int id) {
this.id = id;
} public String toString() {
return "key="+id;
} public int hashCode() {
return id;
} public boolean equals(Object o) {
return o instanceof User && (id == ((User) o).id);
}
}
执行MAIN方法输出结果:
[key=2, key=1, key=3]
1
截取think in java一段描述:
equals()相等的两个对象,hashcode()一定相等;
equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。换句话说,equals()方法不相等的两个对象,hashcode()有可能相等。(我的理解是由于哈希码在生成的时候产生冲突造成的)。
反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。解释下第3点的使用范围,我的理解是在object、String等类中都能使用。在object类中,hashcode()方法是本地方法,返回的是对象的地址值,而object类中的equals()方法比较的也是两个对象的地址值,如果equals()相等,说明两个对象地址值也相等,当然hashcode()也就相等了;在String类中,equals()返回的是两个对象内容的比较,当两个对象内容相等时,
Hashcode()方法根据String类的重写代码的分析,也可知道hashcode()返回结果也会相等。以此类推,可以知道Integer、Double等封装类中经过重写的equals()和hashcode()方法也同样适合于这个原则。当然没有经过重写的类,在继承了object类的equals()和hashcode()方法后,也会遵守这个原则。
附下哈希表结构:
在一个数组中存储对象时,通过 hashCode 得到的哈希值来计算数组的索引位置(通常是求余运算),然后根据这个索引位置进行存取。多个对象计算出来的索引位置相同(叫hash冲突)时,用链表保存。冲突怎么保证取到的就是自己呢?那么就要用到 Object.equals() 方法。
所以要把对象存储在像 hash table类似的数据结构(比如:HashSet)中,hashCode 与 equals 要成对实现。
部分内容来源:
java--map容器的hashcode和equals的更多相关文章
- 【Java】Map杂谈,hashcode()、equals()、HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap
参考的优秀文章: <Java编程思想>第四版 <Effective Java>第二版 Map接口是映射表的结构,维护键对象与值对象的对应关系,称键值对. > hashco ...
- Java 中正确使用 hashCode 和 equals 方法
在这篇文章中,我将告诉大家我对hashCode和equals方法的理解.我将讨论他们的默认实现,以及如何正确的重写他们.我也将使用Apache Commons提供的工具包做一个实现. 目录: hash ...
- Java中正确使用hashCode() 和equals() 、==
在java编程中,经常会遇到两个对象中某个属性的比较,常常会用到的方法有: == .equals().但是两者使用起来有什么区别呢? 一.== java中的==是比较两个对象在JVM中的地址.比较好理 ...
- java为什么要重写hashCode和equals方法?
如果不被重写(原生)的hashCode和equals是什么样的? 不被重写(原生)的hashCode值是根据内存地址换算出来的一个值. 不被重写(原生)的equals方法是严格判断一个对象是否相等的方 ...
- (转)Java 中正确使用 hashCode 和 equals 方法
背景:最近在编写持久化对象时候遇到重写equals和hashCode方法的情况,对这两个方法的重写做一个总结. 链接:https://www.oschina.net/question/82993_75 ...
- 重写Java Object对象的hashCode和equals方法实现集合元素按内容判重
Java API提供的集合框架中Set接口下的集合对象默认是不能存储重复对象的,这里的重复判定是按照对象实例句柄的地址来判定的,地址相同则判定为重复,地址不同不管内容如何都判定为不重复,这有时与需求不 ...
- Java入门系列之hashCode和equals(十二)
前言 前面两节内容我们详细讲解了Hashtable算法和源码分析,针对散列函数始终逃脱不掉hashCode的计算,本节我们将详细分析hashCode和equals,同时您将会看到本节内容是从<E ...
- Java中正确使用hashCode和equals方法
在这篇文章中,我将告诉大家我对hashCode和equals方法的理解.我将讨论他们的默认实现,以及如何正确的重写他们.我也将使用Apache Commons提供的工具包做一个实现. 目录: hash ...
- 【java编程】重写HashCode和equals方法
[一]重写equals方案的规则 equals方法本来的原则 1.类的每个实例本质上都是唯一的. 2.不关心类是否提供了“逻辑相等”的测试功能 3.超类已经覆盖了equals,从超类继承过来的行为对于 ...
随机推荐
- C++中为什么要用虚函数、指针或引用才能实现多态?
原文链接:http://blog.csdn.net/zoopang/article/details/14071779 学过C++的都知道,要实现C++的多态性必须要用到虚函数,并且还要使用引用或者指针 ...
- IPv6 tutorial 2 New features: Routing
https://4sysops.com/archives/ipv6-part-2-new-features-routing/ Routing路由选择 In the last post of my IP ...
- Running an etcd cluster on localhost
Purpose Run a cluster on localhost while investigating etcd Use a static cluster (So we have no exte ...
- 结构体dict_table_t
typedef struct dict_table_struct dict_table_t; /** Data structure for a database table. Most fields ...
- 调试UnhandledExceptionFilter
kernel32!UnhandledExceptionFilter通过判断当前进程是否附加了调试器,如果附加,就把异常交给调试器,如果没有,就把异常交给进程的UnhandledExceptionFil ...
- GitHub常用 库
来自: http://www.jianshu.com/p/6475c90e8b4d 网络请求库 https://github.com/AFNetworking/AFNetworking https:/ ...
- Objective-C 记录
NSdata 与 NSString,Byte数组,UIImage 的相互转换 原文网址:http://www.cnblogs.com/jacktu/archive/2011/11/08/2241528 ...
- 利用HttpWebRequest和HttpWebResponse获取Cookie
之前看过某个同学的一篇有关与使用JSoup解析学校图书馆的文章,仔细一看,发现竟然是同校!!既然对方用的是java,那么我也就来个C#好了,虽然我的入门语言是java. C#没有JSoup这样方便的东 ...
- 转载--C++ STL
转自:http://wenku.baidu.com/view/15d18b4533687e21af45a9a4.html 1.C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vec ...
- LoadRunner调用Java程序—性能测试-转载
LoadRunner调用Java程序—性能测试 为了充分利用LoadRunner的场景控制和分析器,帮助我们更好地控制脚本加载过程,从而展现更直观有效的场景分析图表.本次将重点讨论LoadRunn ...