java 中hashcode和equals 总结
一、概述
在Java中hashCode的实现总是伴随着equals,他们是紧密配合的,你要是自己设计了其中一个,就要设计另外一个。当然在多数情况下,这两个方法是不用我们考虑的,直接使用默认方法就可以帮助我们解决很多问题。但是在有些情况,我们必须要自己动手来实现它,才能确保程序更好的运作。
1.1 规则
粗略总结一下在JavaDoc中所规定hashcode方法的合约:
Objects that are equal must have the same hash code within a running process。
(在程序执行期间,如果两个对象相等,那么它们的哈希值必须相等)
注意,下面两条常见错误想法:
- Unequal objects must have different hash codes – WRONG!
- Objects with the same hash code must be equal – WRONG!
关于hashcode,你必须知道的三件事:
- Whenever you implement equals, you MUST also implement hashCode
- Never misuse hashCode as a key
- Do not use hashCode in distributed applications
详情见:The 3 things you should know about hashCode()
对于hashCode,我们应该遵循如下规则:
1. 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。
2. 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。
3. 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。
对于equals,我们必须遵循如下规则:
对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。
自反性:x.equals(x)必须返回是“true”。
传递性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。
一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。
任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。
1.2 作用
hashcode:
常被系统用来快速检索对象。
equals:
1、如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
2、String、Date等类对equals方法进行了重写,它们比较的是所指向的对象的内容。
当然在重写equals方法中,可以指定比较对象的地址,如果这样的话,就失去了重写的意义,所以重写,一般是比较对象的内容。
注意:equals方法不能作用于基本数据类型的变量。
1.3 关联
至于hashcode与equals之间的关联关系,我们只需要记住如下即可:
- 如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。
- 如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。
因此,在重写equals方法时,总是重写hashCode方法。改写后equals方法,使得两个不同的实例在逻辑上是相等的;如果不重写hashCode方法,则hashCode判断两个不同实例是不同的;导致违反“如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。”
二、equals详解
2.1 equals的设计指导
public class Person
{
private String name;
private int age;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
@Override
public boolean equals(Object other)
{
// 1、 自反性
if (other == this)
{
return true;
}
// 2、判断空值
if (other == null)
{
return false;
}
// 3、对象所属类的类型判断
if (!getClass().equals(other.getClass()))
{
return false;
}
// 4、对象的类型转换
Person person = (Person) other;
// 5、针对所需比较的域进行比较
if ((name.equals(person.name))&&(age==person.age))
{
return true;
}
return false;
}
}
- getClass
- instanceof
如何选择这两种方式呢?
如果子类能够拥有自己的相等概念,则对称性需求将强制采用getClass进行检测。
如果由超类决定相等的概念,那么就可以使用instanceof进行检测,这样可以在不同子类的对象之间进行相等的比较。
public boolean equals(Object anObject)
{
// 1、自反性判断
if (this == anObject)
{
return true;
}
// 3、类型判断
if (anObject instanceof String)
{
///4、类型转换
String anotherString = (String) anObject;
///5、针对所需比较的域进行比较
int n = value.length;
if (n == anotherString.value.length)
{
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0)
{
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
虽然,String没有对null值判断,但在其注释有解释:
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
三、hashCode详解
3.1 hashCode设计指导
1、把某个非零常数值(一般取素数),例如17,保存在int变量result中;2、对于对象中每一个关键域f(指equals方法中考虑的每一个域),计算int类型的哈希值c:
- boolean型,计算(f ? 0 : 1);
- byte,char,short型,计算(int)f;
- long型,计算(int) (f ^ (f>>>32));
- float型,计算Float.floatToIntBits(afloat);
- double型,计算Double.doubleToLongBits(adouble)得到一个long,然后再执行long型的计算方式;
- 对象引用,递归调用它的hashCode方法;
- 数组域,对其中每个元素调用它的hashCode方法。
3、步骤2中,计算得到的散列码保存到int类型的变量c中,然后再执行result=31*result+c;(其中31可以自选,最好是素数)
4、最后返回result。
@Override
public int hashCode()
{
int result = 17;
result = 31 * result + age;
result = 31 * result + stringToHashCode(name);
return result;
} private int stringToHashCode(String str)
{
int result = 17;
if (str.length()>0)
{
char[] value = str.toCharArray();
for (int i = 0; i < value.length; i++)
{
char c = value[i];
result = 31 * result + c;
}
}
return result;
}
/** The value is used for character storage. */
private final char value[]; /** Cache the hash code for the string */
private int hash; // Default to 0 public int hashCode()
{
int h = hash;
if (h == 0 && value.length > 0)
{
char val[] = value; for (int i = 0; i < value.length; i++)
{
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
参考:
5、Java核心技术卷1
java 中hashcode和equals 总结的更多相关文章
- java中hashcode()和equals()的详解
今天下午研究了半天hashcode()和equals()方法,终于有了一点点的明白,写下来与大家分享(zhaoxudong 2008.10.23晚21.36). 1. 首先equals()和hashc ...
- Java中hashcode,equals和==
hashcode方法返回该对象的哈希码值. hashCode()方法可以用来来提高Map里面的搜索效率的,Map会根据不同的hashCode()来放在不同的位置,Map在搜索一个对象的时候先通过has ...
- java中hashcode和equals的区别和联系
HashSet和HashMap一直都是JDK中最常用的两个类,HashSet要求不能存储相同的对象,HashMap要求不能存储相同的键. 那么Java运行时环境是如何判断HashSet中相同对象.Ha ...
- java中hashCode()与equals()详解
首先之所以会将hashCode()与equals()放到一起是因为它们具备一个相同的作用:用来比较某个东西.其中hashCode()主要是用在hash表中提高 查找效率,而equals()则相对而言使 ...
- java中 hashCode() 和 equals()
1. 值类型是存储在内存中的栈,而引用类型的变量在栈中仅仅是存储引用类型变量的地址来自堆,而其本身则存储在栈中. 2. ==操作比较的是两个变量的值是否相等, 3. 对于引用型变量表示的是两个变量在堆 ...
- 深入探究Java中hashCode()和equals()的关系
目录 一.基础:hashCode() 和 equals() 简介 equals() hashCode() 二. 漫谈:初识 hashCode() 与 equals() 之间的关系 三. 解密:深入理解 ...
- Java中HashCode()和equals()的作用
引言 我们知道Java中的集合(Collection)大致可以分为两类,一类是List,再有一类是Set. 前者集合内的元素是有序的,元素可以重复:后者元素无序,但元素不可重复. 这里就引出一个问题: ...
- Java中hashCode、equals、==的区别
ref:http://www.cnblogs.com/skywang12345/p/3324958.html 1.==作用: java中的==用来判断两个对象的地址是否相等:当对象是基本数据类型时,可 ...
- java中hashCode和equals什么关系,hashCode到底怎么用的
Object类的hashCode的用法:(新手一定要忽略本节,否则会很惨) 马 克-to-win:hashCode方法主要是Sun编写的一些数据结构比如Hashtable的hash算法中用到.因为ha ...
随机推荐
- [C#源码]VS各版本转换器(支持VS2012,VS2013)
项目名称:[C#源码]VS各版本转换器(支持VS2012,VS2013) 下载内容: (C#源码)VS各版本转换器 实现功能: 支持vs2003-vs2013的各版本转换,由高到低,由低到高都支持. ...
- sgu 101 无向图有双重边的欧拉路径
#include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> ...
- poj 1904 King's Quest tarjan求二分图的所有可选最大匹配边
因为是完美匹配,所以每个点都已经匹配了,那么如果要选择一条别的边,增光路的最后必定找到原来所匹配的点,加上匹配的边,那么就是一个环.所以可选边在一个强连通分量里. #include <iostr ...
- Distributed locks with Redis--官方
原文:http://redis.io/topics/distlock Distributed locks with Redis Distributed locks are a very useful ...
- 聊聊 iOS 开发中的协议
前言 何为协议,简单来说在OC中我们使用关键字@protocol可以声明一个协议,并在协议中添加多个属性.方法供于遵循者实现,从某个角度上来说,这是一种不同于category机制的category.在 ...
- Java基础知识强化之网络编程笔记12:TCP之TCP协议上传文本文件并给出反馈
1. 客户端: package cn.itcast_12; import java.io.BufferedReader; import java.io.BufferedWriter; import j ...
- js中点击事件方法三种方式的区别
在javascript中,可以为某个元素指定事件,指定的方式有以下三种: 1.在html中,使用onclick属性 2.在javascript中,使用onclick属性 (1)注意函数名没有双引号. ...
- h5拖放-拖拽购物车
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- SQL Server 中添加用户
在对象资源管理器中点击安全性,选择登录名-新建登录名
- hadoop学习记录(零)
这个博客开通快一年了,但是由于种种原因,始终没有能够养成定期更新的习惯. 最近完成了比赛的项目,向除了android开发以外再拓宽一下自己的技能树. 最近购买了<java8函数式编程>和& ...