Java中hashcode,equals和==
hashcode方法返回该对象的哈希码值。
hashCode()方法可以用来来提高Map里面的搜索效率的,Map会根据不同的hashCode()来放在不同的位置,Map在搜索一个对象的时候先通过hashCode()找到相应的位置,然后再根据equals()方法判断这个位置上的对象与当前要插入的对象是不是同一个。若两个对象equals相等,但不在一个区间,根本没有机会进行比较,会被认为是不同的对象。
所以,Java对于eqauls方法和hashCode方法是这样规定的:
1、如果两个对象相同,那么它们的hashCode值一定要相同,也告诉我们重写equals方法,一定要重写hashCode方法;
2、如果两个对象的hashCode相同,它们并不一定相同
hashCode()和equals()定义在Object类中,这个类是所有java类的基类,所以所有的java类都继承这两个方法。
注意到hashCode方法前面有个native的修饰符,这表示hashCode方法是由非java语言实现的,说明是一个本地方法,它的实现是根据本地机器相关的。具体的方法实现在外部,返回内存对象的地址。
/**
* Returns a hash code value for the object. This method is
* supported for the benefit of hashtables such as those provided by
* <code>java.util.Hashtable</code>.
* <p>
* The general contract of <code>hashCode</code> is:
* <ul>
* <li>Whenever it is invoked on the same object more than once during
* an execution of a Java application, the <tt>hashCode</tt> method
* must consistently return the same integer, provided no information
* used in <tt>equals</tt> comparisons on the object is modified.
* This integer need not remain consistent from one execution of an
* application to another execution of the same application.
* <li>If two objects are equal according to the <tt>equals(Object)</tt>
* method, then calling the <code>hashCode</code> method on each of
* the two objects must produce the same integer result.
* <li>It is <em>not</em> required that if two objects are unequal
* according to the {@link java.lang.Object#equals(java.lang.Object)}
* method, then calling the <tt>hashCode</tt> method on each of the
* two objects must produce distinct integer results. However, the
* programmer should be aware that producing distinct integer results
* for unequal objects may improve the performance of hashtables.
* </ul>
* <p>
* As much as is reasonably practical, the hashCode method defined by
* class <tt>Object</tt> does return distinct integers for distinct
* objects. (This is typically implemented by converting the internal
* address of the object into an integer, but this implementation
* technique is not required by the
* Java<font size="-2"><sup>TM</sup></font> programming language.)
*
* @return a hash code value for this object.
* @see java.lang.Object#equals(java.lang.Object)
* @see java.util.Hashtable
*/
public native int hashCode();
在java类中可以重写这两个方法,下面是String类中这两个类的实现。
/**
* 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.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
/**
* Returns a hash code for this string. The hash code for a
* <code>String</code> object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote>
* using <code>int</code> arithmetic, where <code>s[i]</code> is the
* <i>i</i>th character of the string, <code>n</code> is the length of
* the string, and <code>^</code> indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
public int hashCode() {
int h = hash;
int len = count;
if (h == 0 && len > 0) {
int off = offset;
char val[] = value; for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
String类中equals是基于内容的比较,而不是基于地址的比较。
Java语言对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”。
以上这五点是重写equals()方法时,必须遵守的准则,如果违反会出现意想不到的结果,请大家一定要遵守。
java中==、equals()、hashCode()都和对象的比较有关,在java中这三者各有什么用处呢,即java中为什么需要设计这三种对象的比较方法呢?
关于==
==是容易理解的。java设计java就是要比较两个对象是不是同一个对象。
对于引用变量而言,比较的时候两个引用变量引用的是不是同一个对象,即比较的是两个引用中存储的对象地址是不是一样的。
对于基本数据类型而言,比较的就是两个数据是不是相等,没什么歧义。
由于对于基本数据类型而言,没有方法,所以不存在equal()和hashCode()的问题,下面的讨论都是针对引用类型而言的。
关于equals()
为什么java会设计equals()方法?
==比较的是两个对象是否是同一个对象,这并不能满足很多需求。有时候当两个对象不==的时候,我们仍然会认为两者是“相等”的,比如对于String对象,当两个对象的字符串序列是一直的,我们就认为他们是“相等”的。对于这样的需求,需要equals()来实现。对于有这种需求的对象的类,重写其equals()方法便可,具体的“相等”逻辑可以根据需要自己定义。
需要注意的地方
Object中equals()的默认实现是比较两个对象是不是==,即其和==的效果是相同的。
java提供的某些类已经重写了equals()方法。自己写的类,如果需要实现自己的“相等”逻辑,需要重写equals()方法。
关于hashCode()
为什么会设计hashCode()方法?
hashCode()方法返回的就是一个数值,我们称之为hashCode吧。从方法的名称上就可以看出,其目的是生成一个hash码。hash码的主要用途就是在对对象进行散列的时候作为key输入,据此很容易推断出,我们需要每个对象的hash码尽可能不同,这样才能保证散列的存取性能。事实上,Object类提供的默认实现确实保证每个对象的hash码不同(在对象的内存地址基础上经过特定算法返回一个hash码)。
分析到这个地方,看似没什么问题,三者的作用很清晰,好像他们之间也没什么关系。在java的规范上,hashCode()方法和equals()方法确实可以没有关系。
但是!!!!!!!!有一个问题。
问题如下:对于集合类HashSet、HashMap等和hash有关的类(以HashSet为例),是通过hash算法来散列对象的。对HashSet而言,存入对象的流程为:根据对象的hash码,经过hash算法,找到对象应该存放的位置,如果该位置为空,则将对象存入该位置;如果该位置不为空,则使用equals()比较该位置的对象和将要入的对象,如果两个相等,则不再插入,如果不相等,根据hash冲突解决算法将对象插入其他位置。
而java规定对于HashSet判断是不是重复对象就是通过equals() 方法来完成,这就需要在两个对象equals()方法相等的时候,hash码一定相等(即hashCode()返回的值相等)。假设两个对象equals()方法相等的时候,hash码不相等,会出现equals()相等的两个对象都插入了HashSet中,这时不允许的。从而我们有了一下的结论:
结论:对于equals()相等的两个对象,其hashCode()返回的值一定相等
通过上面的分析,对于这个结论是没有异议的。结合前面关于hash码要尽可能不同的要求,现在变成了对于equals()相等的对象hash码要一定相等,而对于equals()不同的对象要尽量做到hash码不同。那么怎么才能保证这一点呢?
重写hashCode()
首先,如何保证“对于equals()相等的对象hash码要一定相等”。
equals()方法中对于对象的比较是通过比较对象中全部或者部分字段来完成的,这些字段集合记为集合A,如果我们计算hash码的时候,如果只是从集合A中选取部分字段或者全部字段来完成便可,因为输入相同,不管经过什么算法,输出一定相同(在方法中调用随机函数?这属于吃饱了撑的!)。如此设计便保证满足了第一个要求。
其次,对于equals()不同的对象要尽量做到hash码不同。
对于这一点的保证就是在设计一个好的算法,让不同的输入尽可能产生不同的输出。
下面就详细介绍一下如何设计这个算法。这个算法是有现成的参考的,算法的具体步骤就是:
[1]把某个非零常数值(一般取素数),例如17,保存在int变量result中;
[2]对于对象中每一个关键域f(指equals方法中考虑的每一个域):
[2.1]boolean型,计算(f ? 0 : 1);
[2.2]byte,char,short型,计算(int)f;
[2.3]long型,计算(int) (f ^ (f>>>32));
[2.4]float型,计算Float.floatToIntBits(afloat);
[2.5]double型,计算Double.doubleToLongBits(adouble)得到一个long,再执行[2.3];
[2.6]对象引用,递归调用它的hashCode方法;
[2.7]数组域,对其中每个元素调用它的hashCode方法。
[3]将上面计算得到的散列码保存到int变量c,然后执行 result=37*result+c;
[4]返回result。
其实其思路就是:先去一个基数,然后对于equals()中考虑的每一个域,先转换成整数,再执行result=37*result+c;
参考
http://blog.csdn.net/naughty610/article/details/7027583
http://www.oschina.net/question/82993_75533
http://crd1991.iteye.com/blog/1473108
http://jingyan.baidu.com/article/ff41162582507512e5823763.html
Java中hashcode,equals和==的更多相关文章
- Java中的equals和hashCode方法
本文转载自:Java中的equals和hashCode方法详解 Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要 ...
- Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例(转)
Java中==.equals.hashcode的区别与重写equals以及hashcode方法实例 原文地址:http://www.cnblogs.com/luankun0214/p/4421770 ...
- java 中hashcode和equals 总结
一.概述 在Java中hashCode的实现总是伴随着equals,他们是紧密配合的,你要是自己设计了其中一个,就要设计另外一个.当然在多数情况下,这两个方法是不用我们考虑的,直 ...
- java集合(3)- Java中的equals和hashCode方法详解
参考:http://blog.csdn.net/jiangwei0910410003/article/details/22739953 Java中的equals方法和hashCode方法是Object ...
- Java中的equals和hashCode方法详解
Java中的equals和hashCode方法详解 转自 https://www.cnblogs.com/crazylqy/category/655181.html 参考:http://blog.c ...
- 转:Java中的equals和hashCode方法详解
转自:Java中的equals和hashCode方法详解 Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要重写这 ...
- 一文搞懂--Java中重写equals方法为什么要重写hashcode方法?
Java中重写equals方法为什么要重写hashcode方法? 直接看下面的例子: 首先我们只重写equals()方法 public class Test { public static void ...
- Java 中的 equals() 和 hashCode()
equals() 和 hashCode() 在 Object 类中以本地方法的形式存在,Java 中所有的类都继承了 Object 类,因此所有的类中都包含了这两个方法.这两个方法在 Java 开发中 ...
- Java中的equals()和hashCode() - 超详细篇
前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的equals()和hashCode() - 详细篇>,希望对大家有帮助,谢谢 文章纯属原创,个人总结难免有差错,如果有,麻烦在评论 ...
随机推荐
- 利用Multi-Probe LSH构建ANN高维索引
感谢大神们的无私奉献精神........因此笔者要坚持开源,专注开源,开源就像在HPU的考试中不像其他人作弊一样,长远来看,会有巨大收获. 一.背景介绍 1.1 相似性搜索简介 高维相似性搜索在音频. ...
- Unity3D 与 objective-c 之间数据交互。iOS SDK接口封装Unity3D接口
原地址:http://www.cnblogs.com/qingjoin/p/3638915.html Unity 3D 简单工程的创建.与Xcode 导出到iOS 平台请看这 Unity3D 学习 创 ...
- POJ 1862
#include <iostream> #include <algorithm> #include <iomanip> #include <cmath> ...
- 【转】前端图片该保存为什么格式?png or jpg?
疑虑: 图片存储为web格式,该用什么格式保存呢?png?jpg?压缩比例该为多大?css spript的优劣?有时候我们可能会因为一张格式不正确的图片而导致设计品质的下降以及页面性能的降低.了解图片 ...
- Java Excel
http://www.cnblogs.com/mingforyou/archive/2013/08/26/3282922.html
- Oracle日期函数
Oracle日期函数用于对Oracle数据库中的日期及时间进行处理. (1)ADD_MONTHS Oracle日期函数返回一个具有与所提供日期相差月份的日期,函数中给出了未来或以前的月份数.语法如下: ...
- Java传入参数个数不确定可用(Type ... values)
/** * 可变长的参数. * 有时候,我们传入到方法的参数的个数是不固定的,为了解决这个问题,我们一般采用下面的方法: * 1. 重载,多重载几个方法,尽可能的满足参数的个数.显然这不是什么好办法. ...
- lintcode 中等题:Majority number II 主元素 II
题目 主元素II 给定一个整型数组,找到主元素,它在数组中的出现次数严格大于数组元素个数的三分之一. 样例 给出数组[1,2,1,2,1,3,3] 返回 1 注意 数组中只有唯一的主元素 挑战 要求时 ...
- org.apache.common.io-FileUtils详解
org.apache.common.io---FileUtils详解 getTempDirectoryPath():返回临时目录路径; public static String getTempDire ...
- 腾讯QQ的开发分客户端软件和服务器端软件
Windows客户端主要是C++ COM/ATL Q+Web 后端C++ CGI ,前端javascript和flash 望采纳 腾讯QQ使用何种开发平台? 腾讯QQ的开发分客户端软件和服务器端软件两 ...