xm_king 发表于 2013-1-15 02:22:15

HashCode和equals方法深度分析

 
         在往HashSet集合中放数据的时候,由于HashSet底层是用HashMap中的Key属性存储的,所以是不能重复的,那他如何判断其不是重复的元素呢.这个时候他判断有两步.
       1.调用元素的hashcode方法,判断两对象的hashCode是否相等,如果不相等,则认为两对象不相等,结束.如果相等,则转入equals方法进行判断.
       2.如果equals方法返回true则,是相等的.如果返回false则是不相等的.结束.这里是最终结果.
       总的归纳是如果在调用hashCode方法时判断了对象不相等那就有了结论.不用调用equals方法了
 
 如要以上推论成立,需要验证四个结论:
        1.这个hashCode方法中返回的结果是永远也不相等的,因此会调用equals方法进行判断,结果是所有元素都打印出来了.
        2.hashCode方法不变,修改equals方法,让其总返回false,结果和1一样.
---->以上两点成立的话,说明hashCode方法返回的值不相等的话,结果就与equals方法无关了.
        3.当把hashCode方法中返回数改成一常量时,equas方法总return false,结果是返回第一个元素;
        4.当把hashCode方法中返回数改成一常量时,equas方法总return ture 结果返回全部元素.
----->以上两点成立的话,说明hashCode方法返回的值相等的话,结果有equals方法控制.
import java.util.HashSet;import java.util.Iterator;public class TestHashSet {/*** @param args*/ public static void main(String[] args) {// TODO Auto-generated method stubHashSet hs= new HashSet();String a="123";hs.add(new Element(a,"mengchao"));hs.add(new Element(a,"mengchao"));hs.add(new Element("1234","mengchao3"));Iterator it=hs.iterator();while(it.hasNext()){   System.out.println(it.next());} }}class Element{private String num; private String name; static int i=0; public Element(String num,String name){this.num=num;this.name=name; }public String toString(){return "学号为:"+num+";————名字为"+name; } public int hashCode(){return i++; } public boolean equals(Object o){Element os = (Element)o;   return true; }}结果:学号为:1234;————名字为mengchao3学号为:123;————名字为mengchao学号为:123;————名字为mengchao        将equals方法中  return true; 改成  return false;结果还是一样.
import java.util.HashSet;import java.util.Iterator;public class TestHashSet {   /*** @param args*/ public static void main(String[] args) {// TODO Auto-generated method stubHashSet hs= new HashSet();String a="123";hs.add(new Element(a,"mengchao"));hs.add(new Element(a,"mengchao"));hs.add(new Element("1234","mengchao3"));    Iterator it=hs.iterator();    while(it.hasNext()){   System.out.println(it.next());} }}class Element{private String num; private String name; //static int i=0; public Element(String num,String name){this.num=num;this.name=name; }public String toString(){return "学号为:"+num+";————名字为"+name; } public int hashCode(){return 3; } public boolean equals(Object o){Element os = (Element)o;   return true;   }}运行结果:学号为:123;————名字为mengchao         将equals方法中  return true; 改成  return false;
 
运行结果:学号为:1234;————名字为mengchao3学号为:123;————名字为mengchao学号为:123;————名字为mengchao       在Object类中定义的几个hashCode约定如下:
       1. 在同一应用中,一个对象的hashCode函数在equals函数没有更改的情况下,无论调用多少次,它都必须返回同一个整数。
       2. 两个对象如果调用equals函数是相等的话,那么调用hashCode函数一定会返回相同的整数。
       3. 两个对象如果调用equals函数是不相等的话,那么调用hashCode函数不要求一定返回不同的整数。
         补充一点我自己的看法,拿HashMap来举例,
       在HashMap中保存元素的值是一个 transient Entry[] table,也就是一个数组。在这里要特别注意Entry的元素,在Entry中它有一个属性next,记录了和本节点具有相同的Hash码的对象。但是它们的Equals方法返回的是false。这也解释了为什么先去判断HashCode值,还要再去判断equals方法了。
          在往HashMap中加入数据的过程是这样的,首先要根据key的hashcode值,根据一定的散列算法,找到对应table上的位置,如果该位置已经有value存在了,那么,判断旧value的key和新插入值的key的equals方法是否相等,如果相等,把旧value替换成新插入值。key不变(因为hashcode和equals都相等,HashMap就认为这两个key是相等的)。如果不相等,则将旧value的entry的next属性设置为新value对应的entry属性(实际上这就是解决hash冲突的一种方法)。
            从HashMap中取出元素的过程和上面刚好相反,在这里就不叙述了。
页: [1]
查看完整版本: HashCode和equals方法深度分析