先看一个例子

首先定义一个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中hashcode()和equals()的详解

hashcode 的作用

java--map容器的hashcode和equals的更多相关文章

  1. 【Java】Map杂谈,hashcode()、equals()、HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap

    参考的优秀文章: <Java编程思想>第四版 <Effective Java>第二版 Map接口是映射表的结构,维护键对象与值对象的对应关系,称键值对. > hashco ...

  2. Java 中正确使用 hashCode 和 equals 方法

    在这篇文章中,我将告诉大家我对hashCode和equals方法的理解.我将讨论他们的默认实现,以及如何正确的重写他们.我也将使用Apache Commons提供的工具包做一个实现. 目录: hash ...

  3. Java中正确使用hashCode() 和equals() 、==

    在java编程中,经常会遇到两个对象中某个属性的比较,常常会用到的方法有: == .equals().但是两者使用起来有什么区别呢? 一.== java中的==是比较两个对象在JVM中的地址.比较好理 ...

  4. java为什么要重写hashCode和equals方法?

    如果不被重写(原生)的hashCode和equals是什么样的? 不被重写(原生)的hashCode值是根据内存地址换算出来的一个值. 不被重写(原生)的equals方法是严格判断一个对象是否相等的方 ...

  5. (转)Java 中正确使用 hashCode 和 equals 方法

    背景:最近在编写持久化对象时候遇到重写equals和hashCode方法的情况,对这两个方法的重写做一个总结. 链接:https://www.oschina.net/question/82993_75 ...

  6. 重写Java Object对象的hashCode和equals方法实现集合元素按内容判重

    Java API提供的集合框架中Set接口下的集合对象默认是不能存储重复对象的,这里的重复判定是按照对象实例句柄的地址来判定的,地址相同则判定为重复,地址不同不管内容如何都判定为不重复,这有时与需求不 ...

  7. Java入门系列之hashCode和equals(十二)

    前言 前面两节内容我们详细讲解了Hashtable算法和源码分析,针对散列函数始终逃脱不掉hashCode的计算,本节我们将详细分析hashCode和equals,同时您将会看到本节内容是从<E ...

  8. Java中正确使用hashCode和equals方法

    在这篇文章中,我将告诉大家我对hashCode和equals方法的理解.我将讨论他们的默认实现,以及如何正确的重写他们.我也将使用Apache Commons提供的工具包做一个实现. 目录: hash ...

  9. 【java编程】重写HashCode和equals方法

    [一]重写equals方案的规则 equals方法本来的原则 1.类的每个实例本质上都是唯一的. 2.不关心类是否提供了“逻辑相等”的测试功能 3.超类已经覆盖了equals,从超类继承过来的行为对于 ...

随机推荐

  1. Redisson使用起来很方便,但是需要redis环境支持eval命令

    Redisson使用起来很方便,但是需要redis环境支持eval命令,否则一切都是悲剧,比如me.结果还是要用RedisCommands去写一套.例子就如下,获得一个RLock锁对象,然后tryLo ...

  2. java里的静态变量是放在了堆内存还是栈内存?

    堆区: 1.存储的全部是对象,每个对象都包含一个与之对应的class的信息.(class的目的是得到操作指令) 2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对 ...

  3. 转自 z55250825 的几篇关于FFT的博文(二)

    题目大意:高精度乘法.     fft的实现貌似有很多种,咱先写的是一种递归的fft,应该算是比较快的了吧.参考了 Evil君 的代码,那个运算符重载看的咱P党泪流满面. (没想到P竟然有运算符重载咩 ...

  4. -_-#【CSS 优化】

    高性能CSS 关于css通配符性能问题不完全测试 CSS的渲染效率 border: none; /* 不写 border: 0; 但几乎都是写 border: 0;的.. */ 不要使用过小的图片做背 ...

  5. easyui plugin —— etreegrid:CRUD Treegrid

    昨天写了一个ko+easyui的同样的实现,感觉写的太乱,用起来十分麻烦,于是今天照着edatagrid,写了一个etreegrid,这样再用ko绑定就方便多了. 使用很简单,$(tableId).e ...

  6. c语言诊断_断言库函数#include<assert.h>

    诊断<assert.h>  assert #include <assert.h> void assert(int exp); assert宏用于为程序增加诊断功能.当asser ...

  7. myeclipse安装svn插件的多种方式

          开发者服务评测征文 十万现金悬赏大神 方法一:在线安装 1.打开HELP->MyEclipse Configuration Center.切换到SoftWare标签页. 2.点击Ad ...

  8. JAVA与.NET的相互调用——通过Web服务实现相互调用

    JAVA与.NET是现今世界竞争激烈的两大开发媒体,两者语言有很多相似的地方.而在很多大型的开发项目里面,往往需要使用两种语言进行集成开发.而很多的开发人员都会偏向于其中一种语言,在使用集成开发的时候 ...

  9. HNU13377:Book Club 二分图

    题意:有n个人,m种需求,给出m行,每行a,b代表a想要的书在b那里,问能不能通过交换的方法来满足每个人的需求 思路:要符合题意的话一定是二分图.网上还一种dfs #include<cstdio ...

  10. 【原创】MapReduce编程系列之表连接

    问题描述 需要连接的表如下:其中左边是child,右边是parent,我们要做的是找出grandchild和grandparent的对应关系,为此需要进行表的连接. Tom Lucy Tom Jim ...