关于如何重写hashcode方法的方法

关于何时重写hashCode()?怎样重写hashCode()?
&&&&&&&打个比方,hashCode()&方法是好比是字典前面的目录,有了这个目录你查东西就会快的多,equals方法是比较的内容,就好比根据目录查内容。同一个的内容自然要有唯一的目录,所以hashCode和equals方法一般一起实现。比如Student类的equals方法根据name,school,age重写的,那么hashCode也要根据这三个属性去散列存储的地址。hash表的数据结构是链表的数组,即每个数组元素都是一个链表,链表中存的是hashCode值相等的元素,所以根据hashCode能快速的查找。但是hashCode的具体写法要依据情况去写,没固定写法。&
如何重写hashcode()与equals()&&&&首先,这两个方法都来自于Object对象,根据API文档查看下原意。
(1)public&boolean&equals(Object&obj),对于任何非空引用值&x&和&y,当且仅当&x&和&y&引用同一个对象时,此方法才返回&true;注意:当此方法被重写时,通常有必要重写&hashCode&方法,以维护&hashCode&方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
(2)public&int&hashCode()&返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如java.util.Hashtable&提供的哈希表。我们知道,如果不重写equals,那么比较的将是对象的引用是否指向同一块内存地址,重写之后目的是为了比较两个对象的value值是否相等。特别指出,此时,利用equals比较八大包装对象(如int,float等)和String类(因为该类已重写了equals和hashcode方法)对象时,默认比较的是值,在比较其它对象都是比较的引用地址。那产生了一个问题,为什么jdk中希望我们在重写equals时,非常有必要重写&hashcode呢?我的理解是hashcode是用于散列数据的快速存取,如利用HashSet/HashMap/Hashtable类来存储数据时,都是根据存储对象的&hashcode值来进行判断是否相同的。这样如果我们对一个对象重写了euqals,意思是只要对象的成员变量值都相等那么euqals就等于&true,但不重写hashcode,那么我们再new一个新的对象,当原对象.equals(新对象)等于true时,两者的hashcode却是不一样的,由此将产生了理解的不一致,如在存储散列集合时(如Set类),将会存储了两个值一样的对象,导致混淆,因此,就也需要重写hashcode。
为了保证这种一致性,必须满足以下两个条件:&&&&&&
(1)当obj1.equals(obj2)为true时,obj1.hashCode()&==&obj2.hashCode()必须为true&&&&
(2)当obj1.hashCode()&==&obj2.hashCode()为false时,obj1.equals(obj2)必须为false&&&&
下面,通过一个简单的例子来验证一下。&&
import&java.util.*;
class&BeanA&{
private&int&i;
public&BeanA(int&i)&{
this.i&=&i;
public&String&toString()&{
return&"&&&"&+&i;
public&boolean&equals(Object&o)&{
BeanA&a&=&(BeanA)&o;
return&(a.i&==&i)&?&true&:&false;
public&int&hashCode()&{
public&class&HashCodeTest&{
public&static&void&main(String[]&args)&{
HashSet&set&=&new&HashSet();
for&(int&i&=&0;&i&&=&3;&i++)&{
set.add(new&BeanA(i));
System.out.println(set);
set.add(new&BeanA(1));
System.out.println(set.toString());
System.out.println(set.contains(new&BeanA(0)));
System.out.println(set.add(new&BeanA(1)));
System.out.println(set.add(new&BeanA(4)));
System.out.println(set);
我们在类BeanA中重写了equals和hashcode方法,这样在存储到HashSet数据集中,将保证不会出现重复的数据;如果把这两个方法去掉后,那些重复的数据仍会存入HashSet中,这就与HashSet强调的元素唯一性相违背,大家可以把这两个方法注释掉再运行一下。&&&因此,我们就可以理解在一些java类中什么情况下需要重写equals和hashcode。比如:在hibernate的实体类中,往往通过一个主键(或唯一标识符)来判断数据库的某一行,这就需要重写这两个方法。因为,Hibernate保证,仅在特定会话范围内,持久化标识(数据库的行)和&Java标识是等价的。因此,一旦&我们混合了从不同会话中获取的实例,如果希望Set有明确的语义,就必&须实现equals()&和hashCode()。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。没有更多推荐了,
不良信息举报
举报内容:
关于为什么要重写hashCode()方法和equals()方法及如何重写
举报原因:
原文地址:
原因补充:
最多只允许输入30个字
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!16:15 提问
Java的如果没有重写hashCode()方法,那么返回的就是这个对象的内存地址吗?
Object o=new Object();
System.out.println(o.hashCode());
打印出来的是不是就是o的内存地址?
按赞数排序
hashcode方法返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表。
hashCode 的常规协定是:
在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
当equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
hashCode 的常规协定是:
在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
有些JVM在实现时是直接返回对象的存储地址,但是大多时候并不是这样,只能说可能存储地址有一定关联。HotSpot JVM就不是
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!
其他相关推荐重写hashCode方法和equals方法的注意事项重写hashCode方法和equals方法的注意事项楚俏女人百家号map/set的key为自定义对象时,必须重写equals方法和hashCode方法重写equals的注意事项Java语言规范要求equals需要具有如下的特性:自反性:对于任何非空引用 x,x.equals() 应该返回 true。对称性:对于任何引用 x 和 y,当且仅当 y.equals(x) 返回 true,x.equals(y) 也应该返回 true。传递性:对于任何引用 x、y 和 z,如果 x.equals(y)返回 true,y.equals(z) 也应返回同样的结果。一致性:如果 x 和 y 引用的对象没有发生变化,反复调用 x.equals(y) 应该返回同样的结果。对于任意非空引用 x,x.equals(null) 应该返回 false。在对象比较时,我们应该如何编写出一个符合特性的 equals 方法呢,《Core Java》中提出了如下建议:显式参数命名为 otherObject,稍后将它转换成另一个叫做 other 的变量。检测 this 与 otherObject 是否引用同一个对象: 这个等式可以避免一个个比较类中的域,实现优化。检测 otherObject 是否为 null,如果为 null,返回 false。进行非空校验是十分重要的。比较 this 与 otherObject 是否属于同一个类。如果每个子类都重写了 equals,使用 getClass 检验:如果所有子类都使用同一个 equals,就用 instanceof 检验:将 otherObject 转换为相应的类型变量。现在可以对所有需要比较的域进行比较了。基本类型使用 == 比较对象使用 equals 比较数组类型的域可以使用静态方法 Arrays.equals检测相应数组元素是否相等如果所有域匹配,则返回 true注意:子类重写父类 equals 方法时,必须完全覆盖父类方法,不能因为类型错误或者其他原因定义了一个完全无关的方法。可以使用 @Override 注解对覆盖父类的方法进行标记,这样编译器便会检测到覆盖过程中的错误。重写 hashCode 的注意事项散列码(hash code)是由对象导出的一个整型值。散列码没有规律,在不同的对象中通过不同的算法生成,Java中生成 hashCode 的策略为(以下说明均摘自 Java API 8):String 类的 hashCode 根据其字符串内容,使用算法计算后返回哈希码。Returns a hash code for this string. The hash code for a String object is computed as s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]Integer 类返回的哈希码为其包含的整数数值。Returns: a hash code value for this object, equal to the primitive int value represented by this Integer object.Object 类的 hashCode 返回对象的内存地址经过处理后的数值。Returns a hash code value for the object. This method is supported for the benefit of hash tables such as those provided by HashMap.注意:equals与hashCode的定义必须一致,两个对象equals为true,就必须有相同的hashCode。例如:如果定义的equals比较的是小猫的 name,那么hashCode就需要散列该 name,而不是小猫的 color 或 size。本文由百家号作者上传并发布,百家号仅提供信息发布平台。文章仅代表作者个人观点,不代表百度立场。未经作者许可,不得转载。楚俏女人百家号最近更新:简介:关注这里邂逅不一样的自己! 作者最新文章相关文章当一个类有可能会和其他类发生比较的时候,我们会重写equals方法,但大多数情况下,都忽略了重写hashCode方法。
这里说一下重写hashCode的必要性。
当我们使用HashSet或者HashMap的时候,在比对value|key是否存在时,会调用hashCode方法。
注意,hashSet的contains方法其实是依赖于HashMap的containsKey方法的。
我们来看下containsKey方法的实现:
public boolean containsKey(java.lang.Object paramObject)
return (getEntry(paramObject) != null);
final Entry&K, V& getEntry(java.lang.Object paramObject)
int i = (paramObject == null) ? 0 : hash(paramObject.hashCode());
Entry localEntry = this.table[indexFor(i, this.table.length)];
for (; localEntry != null;
localEntry = localEntry.next)
if (localEntry.hash == i) { java.lang.Object localO
if (((localObject = localEntry.key) == paramObject) || ((paramObject != null) && (paramObject.equals(localObject))))
return localE } }
return null;
由上面代码即可知,hashCode是重要的判断依据,没有重写hashCode,equals表现相等的两个类,它们的hashCode并不相等。
所以会导致containsKey方法返回false,测试代码如下:
包含HashCode的类:
package hashset.and.
public class ClassWithHashCode {
public int
public boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof ClassWithHashCode) {
ClassWithHashCode code = (ClassWithHashCode)
return code.i ==
return false;
public int hashCode() {
return i * 17 + 37;
没有重写hasCode的类:
package hashset.and.
public class ClassWithoutHashCode {
public int
public boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof ClassWithoutHashCode) {
ClassWithoutHashCode code = (ClassWithoutHashCode)
return code.i ==
return false;
package hashset.and.
import java.util.HashS
public class Test {
* @param args
public static void main(String[] args) {
ClassWithHashCode c1 = new ClassWithHashCode();
ClassWithHashCode c2 = new ClassWithHashCode();
HashSet&ClassWithHashCode& set = new HashSet&ClassWithHashCode&();
set.add(c1);
System.out.println(set.contains(c2));
ClassWithoutHashCode co1 = new ClassWithoutHashCode();
ClassWithoutHashCode co2 = new ClassWithoutHashCode();
co1.i = 0;
co2.i = 0;
HashSet&ClassWithoutHashCode& set1 = new HashSet&ClassWithoutHashCode&();
set1.add(co1);
System.out.println(set.contains(co2));
执行的结果为:
符合预期。证毕。
阅读(...) 评论()}

我要回帖

更多关于 怎么重写hashcode方法 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信