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语言实现的,说明是一个本地方法,它的实现是根据本地机器相关的。具体的方法实现在外部,返回内存对象的地址。

 1  /**
 2      * Returns a hash code value for the object. This method is
 3      * supported for the benefit of hashtables such as those provided by
 4      * <code>java.util.Hashtable</code>.
 5      * <p>
 6      * The general contract of <code>hashCode</code> is:
 7      * <ul>
 8      * <li>Whenever it is invoked on the same object more than once during
 9      *     an execution of a Java application, the <tt>hashCode</tt> method
10      *     must consistently return the same integer, provided no information
11      *     used in <tt>equals</tt> comparisons on the object is modified.
12      *     This integer need not remain consistent from one execution of an
13      *     application to another execution of the same application.
14      * <li>If two objects are equal according to the <tt>equals(Object)</tt>
15      *     method, then calling the <code>hashCode</code> method on each of
16      *     the two objects must produce the same integer result.
17      * <li>It is <em>not</em> required that if two objects are unequal
18      *     according to the {@link java.lang.Object#equals(java.lang.Object)}
19      *     method, then calling the <tt>hashCode</tt> method on each of the
20      *     two objects must produce distinct integer results.  However, the
21      *     programmer should be aware that producing distinct integer results
22      *     for unequal objects may improve the performance of hashtables.
23      * </ul>
24      * <p>
25      * As much as is reasonably practical, the hashCode method defined by
26      * class <tt>Object</tt> does return distinct integers for distinct
27      * objects. (This is typically implemented by converting the internal
28      * address of the object into an integer, but this implementation
29      * technique is not required by the
30      * Java<font size="-2"><sup>TM</sup></font> programming language.)
31      *
32      * @return  a hash code value for this object.
33      * @see     java.lang.Object#equals(java.lang.Object)
34      * @see     java.util.Hashtable
35      */
36     public native int hashCode();

在java类中可以重写这两个方法,下面是String类中这两个类的实现。

 1 /**
 2      * Compares this string to the specified object.  The result is {@code
 3      * true} if and only if the argument is not {@code null} and is a {@code
 4      * String} object that represents the same sequence of characters as this
 5      * object.
 6      *
 7      * @param  anObject
 8      *         The object to compare this {@code String} against
 9      *
10      * @return  {@code true} if the given object represents a {@code String}
11      *          equivalent to this string, {@code false} otherwise
12      *
13      * @see  #compareTo(String)
14      * @see  #equalsIgnoreCase(String)
15      */
16     public boolean equals(Object anObject) {
17     if (this == anObject) {
18         return true;
19     }
20     if (anObject instanceof String) {
21         String anotherString = (String)anObject;
22         int n = count;
23         if (n == anotherString.count) {
24         char v1[] = value;
25         char v2[] = anotherString.value;
26         int i = offset;
27         int j = anotherString.offset;
28         while (n-- != 0) {
29             if (v1[i++] != v2[j++])
30             return false;
31         }
32         return true;
33         }
34     }
35     return false;
36     }

 1 /**
 2      * Returns a hash code for this string. The hash code for a
 3      * <code>String</code> object is computed as
 4      * <blockquote><pre>
 5      * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
 6      * </pre></blockquote>
 7      * using <code>int</code> arithmetic, where <code>s[i]</code> is the
 8      * <i>i</i>th character of the string, <code>n</code> is the length of
 9      * the string, and <code>^</code> indicates exponentiation.
10      * (The hash value of the empty string is zero.)
11      *
12      * @return  a hash code value for this object.
13      */
14     public int hashCode() {
15     int h = hash;
16         int len = count;
17     if (h == 0 && len > 0) {
18         int off = offset;
19         char val[] = value;
20
21             for (int i = 0; i < len; i++) {
22                 h = 31*h + val[off++];
23             }
24             hash = h;
25         }
26         return h;
27     }

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中为什么需要设计这三种对象的比较方法呢?

  1. 关于==

    ==是容易理解的。java设计java就是要比较两个对象是不是同一个对象。

    对于引用变量而言,比较的时候两个引用变量引用的是不是同一个对象,即比较的是两个引用中存储的对象地址是不是一样的。

    对于基本数据类型而言,比较的就是两个数据是不是相等,没什么歧义。

    由于对于基本数据类型而言,没有方法,所以不存在equal()和hashCode()的问题,下面的讨论都是针对引用类型而言的。

  2. 关于equals()

    为什么java会设计equals()方法?

    ==比较的是两个对象是否是同一个对象,这并不能满足很多需求。有时候当两个对象不==的时候,我们仍然会认为两者是“相等”的,比如对于String对象,当两个对象的字符串序列是一直的,我们就认为他们是“相等”的。对于这样的需求,需要equals()来实现。对于有这种需求的对象的类,重写其equals()方法便可,具体的“相等”逻辑可以根据需要自己定义。

    需要注意的地方

    Object中equals()的默认实现是比较两个对象是不是==,即其和==的效果是相同的。

    java提供的某些类已经重写了equals()方法。自己写的类,如果需要实现自己的“相等”逻辑,需要重写equals()方法。

  3. 关于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码不同。那么怎么才能保证这一点呢?

  4. 重写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

时间: 2024-10-07 15:26:53

Java中hashcode,equals和==的相关文章

看Java中==、equals、hashCode的来龙去脉

我有一个哥们去参加了面试,面试官这样问一个Java问题: 你说一下java对象的equals方法调用什么方法呢?我这个哥们想了想,回答说"应该是比较的引用".听了这个答案之后,那个面试官摇头晃脑的说:"不对,你回答的不对,equals方法调用的是hashCode方法".于是乎,我那个技术还不错的哥们就悲壮地栽在这道题目上了. 今天晚上,西安历史上少有的热,那就好好总结一下这个题目的来龙去脉好了,也方便给后面的朋友们提个醒,不要栽在这么简单的问题上.你说这个面试官回答

Java 中的 ==, equals 与 hashCode 的区别与联系

一.概述 1.概念 == : 该操作符生成的是一个boolean结果,它计算的是操作数的值之间的关系 equals : Object 的 实例方法,比较两个对象的content是否相同 hashCode : Object 的 native方法 , 获取对象的哈希值,用于确定该对象在哈希表中的索引位置,它实际上是一个int型整数 二.关系操作符 == 1.操作数的值 基本数据类型变量 在Java中有八种基本数据类型: 浮点型:float(4 byte), double(8 byte) 整型:byt

Java中的equals和hashCode方法

本文转载自:Java中的equals和hashCode方法详解 Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要重写这两个方法. equals()和hashCode()方法是用来在同一类中做比较用的,尤其是在容器里如set存放同一类对象时用来判断放入的对象是否重复.这里我们首先要明白一个问题: equals()相等的两个对象,hashcode()一定相等,equals()不相等的两个对象,却并不能证明他们的h

java 中hashcode和equals 总结

一.概述            在Java中hashCode的实现总是伴随着equals,他们是紧密配合的,你要是自己设计了其中一个,就要设计另外一个.当然在多数情况下,这两个方法是不用我们考虑的,直接使用默认方法就可以帮助我们解决很多问题.但是在有些情况,我们必须要自己动手来实现它,才能确保程序更好的运作. 1.1 规则 粗略总结一下在JavaDoc中所规定hashcode方法的合约:      Objects that are equal must have the same hash co

跟王老师学集合(九)Java中hashCode方法与equals方法的用法

Java中对象比较 主讲人:王少华  QQ群号:483773664 学习目标: 掌握java中的==.equals().hashCode()的异同 一.问题 通过前面的学习,我们知道,Java集合有三个大的接口,List接口.Map接口.Set接口,这三个接口的特点是List接口中的元素能重复.Map接口中的key对象不能重复,Set接口中的元素是不可以重复的.那么问题来了,两个元素是否重复是根据什么来判断的. 二.Java中两个对象比较 (一).== 1.Java中,比较简单类型变量用"==&

Java中的equals和hashCode方法详解

Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要重写这两个方法,今天就来介绍一些这两个方法的作用. equals()和hashCode()方法是用来在同一类中做比较用的,尤其是在容器里如set存放同一类对象时用来判断放入的对象是否重复. 这里我们首先要明白一个问题: equals()相等的两个对象,hashcode()一定相等,equals()不相等的两个对象,却并不能证明他们的hashcode()不相等.换

面试点:Java 中 hashCode() 和 equals() 的关系

Java 中 hashCode() 和 equals() 的关系是面试中的常考点,如果没有深入思考过两者设计的初衷,这个问题将很难回答.除了应付面试,理解二者的关系更有助于我们写出高质量且准确的代码. 一.基础:hashCode() 和 equals() 简介 在学习 hashCode() 和 equals() 之间的关系之前, 我们有必要先单独地了解他俩的特点. equals() equals() 方法用于比较两个对象是否相等,它与 == 相等比较符有着本质的不同. 在万物皆对象的 Java

Java中hashCode的作用

转  http://blog.csdn.net/fenglibing/article/details/8905007 Java中hashCode的作用 2013-05-09 13:54 64351人阅读 评论(17) 收藏 举报  分类: JAVA实用笔记(142)  版权声明:本文为博主原创文章,未经博主允许不得转载. 以下是关于HashCode的官方文档定义: [plain] view plain copy hashcode方法返回该对象的哈希码值.支持该方法是为哈希表提供一些优点,例如,j

[转载]Java中hashCode与equal方法详解

转载自http://blog.csdn.net/jiangwei0910410003/article/details/22739953 Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要重写这两个方法,今天就来介绍一些这两个方法的作用. equals()和hashCode()方法是用来在同一类中做比较用的,尤其是在容器里如set存放同一类对象时用来判断放入的对象是否重复. 这里我们首先要明白一个问题: equa