hashCode equal避免的几个误区

标签: hashcode equal | 发表时间:2012-12-28 11:45 | 作者:
出处:http://www.iteye.com
对于hashcode方法和equals方法,我们需要注意以下几点:
1.equals方法所需要的几个特性
   ?什么情况下进行equals的比较?答案是用equals比较的只是值本身,对于equals方法,读者需要记住按照两种情况来运用,一比较基本类型的值的比较,二比较的是对象。equals比较的只是值或者对象的内容。
   非空的x,y,z,
   一致性:无论x.equals(y)比较多少次,都应该返回true
   反射性:任何对象和它本身比较都应该返回true
   类推性:x.equals(y), y.equals(z),x.equals(z)都应该返回true
   对称性:x.equals(y)和y.equals(x)返回的应该都是true.
   非空和null比较永久都该返回false.
2.hashcode和equals的关系
   对于java中的object类来说,hashcode返回的是对象的内存地址(可以粗略的这样认为),String类(以及其他原生数据类型如int ,flat等的引用数据类型Integer Float等)重写了object的hashcode和equals方法,但是在这里注意,不要被基本数据类型的对于hashcode和equals方法重写所迷惑了。基本数据类型对于OBJECT的该2个方法的重写并不意味着你再现实的代码中也同样照做(下面会解释).基本类型String等对于这两个方法的重写其实着重在内容上。
    Java定义的规则中硬性的绑定了2个原则:
    hashcode值相同的2个对象(注意这里是对象)并不一定是同一个对象,也就是说equals方法返回的不一定是true,即对象的内容可能不同。
    equals方法返回true,hashcode的返回的int类型的值并不一定相同,即内容相同的两个对象不一定是同一个对象(名字相同的人不一定是同一个人)。
    相同对象必定equals方法返回true且hashcode值相同

3.重点关键所在:现实当中重写equals方法必定要重写hashcode?
    读者可以直接读取java的目录中的rt.jar,找到string类的源码,可以发现,String的hashcode方法是读取字符串中的每个字符,并不是对象的内存地址,换句话来说,object的hashcode方法在string中被重写,equals方法也是对2个字符串内容进行比较,hashcode也被定义成与内容相关, 所以我们可以发现为了保证基本类型对象是同一个对象:必须让hashcode返回值和equals方法都绑定到对于内容的处理上,换句话来说,满足了上面第二点的分析,同一个对象hashcode,equals2个方法都必须满足
    现实当中,只有在用到集合类的时候,才需要重写hashcode方法,否则不需要重写hashcode方法,比较2个对象只需要equals方法即可,当用到集合类时,重写hashcode方法并不是效率的考虑,而是必须重写hashcode方法,否则会出现宏观上的理解错误:
    mport java.util.*;
public class HashSetTest
{
   public static void main(String[] args)
    {
                 HashSet hs=new HashSet();
                 hs.add(new Student(1,"t1"));
                 hs.add(new Student(2,"t2"));
                 hs.add(new Student(3,"t3"));
                 hs.add(new Student(1,"t1"));
 
                 Iterator it=hs.iterator();
                 while(it.hasNext())
                 {
                        System.out.println(it.next());
                 }
     }
}
class Student
   {
     int num;
     String name;
     Student(int num,String name)
                {
                this.num=num;
                 this.name=name;
                 }
              public String toString()
                {
                    return num+":"+name;
                 }
           }     
输出结果为:
                      1:t1
                   1:t1
                   3:t3
                   2:t2

可见这样的效果并不是我们从宏观上想要的,对于我们自己定义的对象student来说,我们需要num,name相同的对象就应当是同一个对象,但是由于没有重写equals方法和hashcode方法,使用new 运算符创建对象时,内存地址是不同的,因为沿用了object的hashcode和equals方法,导致set对传入的对象的判断上发生错误,导致我们重复塞了2个“相同的对象”(这种相同是指我们自己定义的规则,比如学号相同,名称相同我们就认为是同一个对象)。


读者可以查看HashSet的源码,可以发现HashSet底层采用HashMap实现,HashMap并不允许重复的K值存入,所以当存入新的K时,会对传入的参数K的hashCode值进行判断,如果K相同,那么覆盖老的V,用新的V:
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
我们可以发现这里双重调用到了hash和equals,所以为了避免存入重复对象,我们需要重写我们自己的student类的hashcode和equals方法,以告诉hashSet避免存入我们宏观意义上的重复对象。
而对于String等基本类型来说,比如
HashSet hs=new HashSet();
                 hs.put("1","2");
                 hs.put("1","3"); //第二步
当进行put时,代码第二步处会对传入的"1"(K)进行判断,因为已经存在一个K的hashcode以及equals方法和第二步处传入的"1"相同,所以视作同一个K处理。



最后总结一点:一般项目中如果需要用到集合类如hashtable,hashset时,那么我们自己新建的对象如果需要存入该集合类,那么必须重写hashcode以及equals方法,不能漏掉任何一个。
  

已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [hashcode equal] 推荐:

关于hashcode与equal函数

- - 编程语言 - ITeye博客
hashcode:独一无二地代表了一个对象,并且通过hashcode可以找到这个对象. 在java.lang.Object的规范中,对hasCode有如下的约定:.  1 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,那么对该对象调用多次hashCode方法,它必须返回相同的整数.

hashCode equal避免的几个误区

- - ITeye博客
对于hashcode方法和equals方法,我们需要注意以下几点:. 1.equals方法所需要的几个特性.    ?什么情况下进行equals的比较. 答案是用equals比较的只是值本身,对于equals方法,读者需要记住按照两种情况来运用,一比较基本类型的值的比较,二比较的是对象. equals比较的只是值或者对象的内容.

重写equal 的同时为什么必须重写hashcode?

- - Java - 编程语言 - ITeye博客
hashCode是编译器为不同对象产生的不同整数,根据equal方法的定义:如果两个对象是相等(equal)的,那么两个对象调用hashCode必须产生相同的整数结果,即:equal为true,hashCode必须为true,equal为false,hashCode也必须为false,所以必须重写hashCode来保证与equal同步.

java中的hashcode作用

- - 编程语言 - ITeye博客
根据API文档,java中的hashcode事实上是跟equals是有着密切联系的,hashcode是为了提高哈希表的性能. public int hashCode()返回该对象的哈希码值. 支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能. 说明是一个本地方法,它的实现是根据本地机器相关的.

为什么要重写equles和hashcode

- - 编程语言 - ITeye博客
  经过网上查阅资料得出如下结论.                      大家知道,Java中的集合(Collection)有两类,一类是List,再有一类是Set. 前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复. 那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢.

hashCode()方法的性能优化

- - 并发编程网 - ifeve.com
原文链接, 译文链接,原文作者: Robert Nystrom,译者:有孚. 本文主要讨论下不同的hashCode()的实现对应用程序的性能影响. hashCode()方法的主要目的就是使得一个对象能够成为hashMap的key或者存储到hashset中. 这种情况下对象还得实现equals(Object)方法,它的实现和hashCode()必须是一致的:.

【转】java中hashcode()和equals()的详解

- - 互联网 - ITeye博客
首先equals()和hashcode()这两个方法都是从object类中继承过来的. equals()方法在object类中定义如下: . 很明显是对两个对象的地址值进行的比较(即比较引用是否相同). 但是我们必需清楚,当String 、Math、还有Integer、Double. 等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法.

hashcode和equals区别和联系

- - Java - 编程语言 - ITeye博客
[size=x-small]HashCode和equal方法的区别和联系[/size]. HashCode 和 equal方法重载. 1、 为什么要重载equal方法. 答案:因为Object的equal方法默认是两个对象的引用的比较,意思就是指向同一内存,地址则相等,否则不相等;如果你现在需要利用对象里面的值来判断是否相等,则重载equal方法.

[转]《Effective Java》中推荐的hashCode算法

- - 荒岛码农
Google首席Java架构师Joshua Bloch在他的著作《Effective Java》中提出了一种简单通用的hashCode算法:. 初始化一个整形变量,为此变量赋予一个非零的常数值,比如int result = 17;. 选取equals方法中用于比较的所有域,然后针对每个域的属性进行计算:.

详解 equals() 方法和 hashCode() 方法

- - ImportNew
Java的基类Object提供了一些方法,其中equals()方法用于判断两个对象是否相等,hashCode()方法用于计算对象的哈希码. equals()和hashCode()都不是final方法,都可以被重写(overwrite). 本文介绍了2种方法在使用和重写时,一些需要注意的问题. Object类中equals()方法实现如下:.