java中hashCode和equals什么关系,hashCode到底怎么用的

Object类的hashCode的用法:(新手一定要忽略本节,否则会很惨)
马克-to-win:hashCode方法主要是Sun编写的一些数据结构比如Hashtable的hash算法中用到。因为hash很快,所以你往 Hashtable里放东西的时候,他先比一下,里面有没有现有的东西的hashCode和你一样,如果都不一样,证明是新的,就不再运行equals方法了,直接放进Hashtable里了,很快。如果放的时候,Hashtable里面现有的某东西的hashCode和他一样,他再运行一下 equals,如不一样,则证明是新的,可以放入。equals也一样,证明确实是一样的,不让放入Hashtable。另外,Object的hashCode方法(Sun公司编的)是返回对象的内部地址。equals原始方法判断两个Object是否a==b,内存地址是否等(以下摘自sun的文档:As much as is reasonably practical, the hashCode method defined by class Object 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 JavaTM programming language.)
马克- to-win:马克 java社区:防盗版实名手机尾号: 73203。



最后,补充一点,Sun公司Object的equals方法文档上指明:for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true). Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes. 假如两个对象的equals返回值一样,hashcode返回值必须一样。但是反过来hashcode等,未必equals等,这就是刚才我们说先判断 hashcode是否等,即使等,也要再运行equals,判断是否真的等。马克-to-win:从现实看,按照这逻辑编程,是效率最高,最合理的,本文这里的例子之所以没按照这条,只是为了说明本文所讲的问题。




例2.1.2.1(hashCode都不一样)---本章源码

import java.util.*;
class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
    public boolean equals(Object o) {
        System.out.println("equals被调用");
/*下句话,假如不是CompanyMark_to_win类型,马克-to-win:就返回假*/    
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下转型
        return name.equals(c.name);//这个equals是String的方法
    }
    public int hashCode() {
        System.out.println("hashCode 被调用 "+super.hashCode());
        return super.hashCode();
    }
}
public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc");
        System.out.println("c1.equals(c2): " + c1.equals(c2));//这个equals会调用子类CompanyMark_to_win的方法,马克-to-win:
        HashSet set = new HashSet();
set.add(c1);
        set.add(c2);
        System.out.println("set size:"+ set.size());
        Hashtable ht = new Hashtable();
        ht.put(c1, 1);
        System.out.println("一样吗?"+ht.containsKey(c2));
    }
}

输出结果:

equals被调用
c1.equals(c2): true
hashCode 被调用 31168322
hashCode 被调用 17225372
set size:2
hashCode 被调用 31168322
hashCode 被调用 17225372
一样吗?false




结果分析:

当把c1和c2放入HashSet和Hashtable时,每次放一个对象,就会调用一次HashCode方法。而这里的hashCode是父类 Object的,所以返回内部地址,不一样。于是HashSet加进去了,size为2,Hashtable也认为c1和c2不一样。HashSet和Hashtable通过 hashCode方法认为c1和c2不一样,即使equals说一样都没用,因为hashcode不一样,就不运行equals了。

例2.1.2.1_b(上例的简版,省略了hashCode方法,直接用父类的)---本章源码

import java.util.*;
class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
    public boolean equals(Object o) {
        System.out.println("equals被调用");
/*下句话,假如不是CompanyMark_to_win类型,马克-to-win:就返回假*/    
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下转型
        return name.equals(c.name);//这个equals是String的方法
    }
}
public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc");
        System.out.println("c1.equals(c2): " + c1.equals(c2));//这个equals会调用子类CompanyMark_to_win的方法,马克-to-win:
        HashSet set = new HashSet();
        set.add(c1);
        set.add(c2);
        System.out.println("set size:"+ set.size());
        Hashtable ht = new Hashtable();
        ht.put(c1, 1);
        System.out.println("一样吗?"+ht.containsKey(c2));
    }
}

输出结果:

equals被调用
c1.equals(c2): true
set size:2
一样吗?false




例2.1.2.2(hashcode一样,equals不一样。)---本章源码

import java.util.*;
class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
    public boolean equals(Object o) {
        System.out.println("equals被调用");
/*下句话,假如不是CompanyMark_to_win类型,马克-to-win:就返回假*/    
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下转型
        return name.equals(c.name);//这个equals是String的方法
    }
    public int hashCode() {
        System.out.println("hashCode 被调用 ");
        return 5;
    }
}
public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc1");
        System.out.println("c1.equals(c2): " + c1.equals(c2));//这个equals会调用子类CompanyMark_to_win的方法,马克-to-win:
        HashSet set = new HashSet();
        set.add(c1);
        set.add(c2);
        System.out.println("set size:"+ set.size());
        Hashtable ht = new Hashtable();
        ht.put(c1, c1);
        System.out.println("一样吗?"+ht.containsKey(c2));   
    }
}

输出结果:

equals被调用
c1.equals(c2): false
hashCode 被调用
hashCode 被调用
equals被调用
set size:2
hashCode 被调用
hashCode 被调用
equals被调用
一样吗?false


结果分析:本例hashcode一样,所以equals方法被调用,equals返回值不一样,所以HashSet和Hashtable都认为c1和c2是不同的对象,都接受了, size等于2。




例2.1.2.2(hashcode一样,equals也一样。)---本章源码

import java.util.*;
class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
    public boolean equals(Object o) {
        System.out.println("equals被调用");
/*下句话,假如不是CompanyMark_to_win类型,马克-to-win:就返回假*/    
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下转型
        return name.equals(c.name);//这个equals是String的方法
    }
    public int hashCode() {
        System.out.println("hashCode 被调用 ");
        return 5;
    }
}
public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc");
        System.out.println("c1.equals(c2): " + c1.equals(c2));//这个equals会调用子类CompanyMark_to_win的方法,马克-to-win:
        HashSet set = new HashSet();
        set.add(c1);
        set.add(c2);
        System.out.println("set size:"+ set.size());
        Hashtable ht = new Hashtable();
        ht.put(c1, 1);
        System.out.println("一样吗?"+ht.containsKey(c2));
    }
}

输出结果:
equals被调用
c1.equals(c2): true
hashCode 被调用
hashCode 被调用
equals被调用
set size:1
hashCode 被调用
hashCode 被调用
equals被调用
一样吗?true

结果分析:本例hashcode一样,所以equals方法被调用,equals返回值一样,所以HashSet和Hashtable都认为c1和c2是相同的对象,只接受了1个, size等于1。