2019-03-19

对象的 equals 和 hashCode

JAVA 两个对象不同为什么他们的hashcode有可能相同
浅谈Java的hashcode方法
为什么在定义hashcode时要使用31这个数呢?
Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例

equals

equals 直接就是判断对象的内存地址是不是相同

    public boolean equals(Object obj) {
        return (this == obj);
    }

hashCode

Object对象的hashCode方法如下

public native int hashCode();

java代码中没有实现。使用native关键字说明这个方法是原生函数,也就是这个方法是用C/C++语言实现的,并且被编译成了DLL,由java去调用。这些函数的实现体在DLL中,JDK的源代码中并不包含,你应该是看不到的。对于不同的平台它们也是不同的。这也是java的底层机制,实际上java就是在不同的平台上调用不同的native方法实现对操作系统的访问的。 String对象的hashCode方法

public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

需要HashCode.每个对象根据值计算HashCode,这个code大小虽然不奢求必须唯一(因为这样通常计算会非常慢),但是要尽可能的不要重复,因此基数要尽量的大。另外,31 * N可以被编译器优化为左移5位后减1即31 * N = (N<<5)-1,有较高的性能。使用31的原因可能是为了更好的分配hash地址,并且31只占用5bits! 所以从效率上 它是2的5次减1,对计算机来说2的乘除操作只需要做位移操作,例如*32就是左移5位。 也就是说31对计算机的角度来说运算更快、切占内存不多不少,而且形成惯例,虚拟机甚至都专门对他做了优化。所以常用31做系数算hashcode 。

equals 和 hashCode 的关系

A.equals(B)==true --> A.hashCode()==B.hashCode() 两个对象,如果调用equals方法得到的结果为true,则两个对象的hashcode值必定相等;反过来就不成立,因为不同的对象可能会生成相同的hashcode值;

重写 equals 时有必要重写 hashCode

当重写了equals方法后,要重写hashCode方法,以维护上面推导的成立。
利用HashSet/HashMap/Hashtable类来存储数据时,都是根据存储对象的hashcode值来进行判断是否相同的。 这样如果我们对一个对象重写了euqals,意思是只要对象的成员变量值都相等那么euqals就等于true,但不重写hashcode,那么我们再new一个新的对象,当原对象.equals(新对象)等于true时,两者的hashcode却是不一样的,由此将产生了理解的不一致。