Java基础:Object类中的equals与hashCode方法

前言java

  这个系列的文章主要用来记录我在学习和复习Java基础知识的过程当中遇到的一些有趣好玩的知识点,但愿你们也喜欢。程序员

一切皆对象面试

   对于软件工程来讲面向对象编程有一套完整的解决方案:OOA、OOD、OOP,  做为程序员来说,OOP实际上是直接接触最多的。Java中OOP最直接的体现就是java.lang.Object了,一切都是对象(除了原生类型,原生类型的 PrimitiveClass对象由JVM启动时生成和加载),Object类主要就只有这么几个方法,其中getClass是反射的基石,notify、notifyAll、wait是多线程并发时经常使用的方法,其中比较有意思的就是hashCode与equals了,也是面试的时候面试官很喜欢问的一个问题。编程

public class Object {

    private static native void registerNatives();
    static {
        registerNatives();
    }

    // finnal的本地方法,子类不能重写
    public final native Class<?> getClass();
    public final native void notify();
    public final native void notifyAll();
    public final native void wait(long timeout) throws InterruptedException;

    // 本地方法wait的包装方法
    public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException("nanosecond timeout value out of range");
        }
        if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
            timeout++;
        }
        wait(timeout);
    }
    public final void wait() throws InterruptedException {
        wait(0);
    }

    // 为何hashCode是本地方法,而equals倒是成员方法呢?
    public native int hashCode();

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

    protected native java.lang.Object clone() throws CloneNotSupportedException;

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

    // 对象成员方法,对象被回收时执行的方法,通常不用来释放资源,由于GC的时机对程序员来讲是不可控的
    protected void finalize() throws Throwable { }

}
View Code

equals与hashCode多线程

  面试题的标准答案是:若是两个对象ab知足a.equals(b) == true,则它们的散列码(hash code)应当要相同,反之则不必定。这里也就引伸出:重写了类的equals方法以后必定要重写hashCode方法,这种状况最多见的是在entity bean中,当bean跟容器类搭配使用时若是重写了equals而没重写hashCode就会引发问题,这里先来看看HashMap的getEntry方法,循环中就是先判断两个对象的hash值(由对象的hashCode计算获得)是否相等,再判断两个对象是否为同一对象最后才调equals方法来判断,这样能够减小equals方法的调用次数,提高容器的性能,若是你们看看Java容器类的源码就会发现大神们对hash思想的运用简直炉火纯青(生活中哈希的应用也随处可见:年月日、时分秒就是对时间流的哈希散列)并发

    final Entry<K,V> getEntry(Object key) {
        int hash = (key == null) ? 0 : hash(key);
        for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
        }
        return null;
    }

 下面是一张抽象化的对比图:ide

hashCode通常是一个int值,比较两个对象的hashCode就是比较两个int值,Java中对原生类型操做的性能确定要好于对方法的调用,因此咱们才会在Java容器中看到那么多对hash的应用。性能

上面这张图也能够直观看出为何说两个对象equals为true的话hashCode就必定相同,反之则不必定。学习

equals方法的四大特性this

  经过equals方法的注解就能清晰看到Java大神们给咱们总结的4大特性了(若是在面试中遇到equasl和hashCode的问题时一遍把四大特性阐述一下会是个小小的加分项):

  一、自反性:本身跟本身比较返回true

  二、对称性:x.equals(y) == y.equals(x)

  三、传递性:x.equals(y) == truey.equals(z) == truex.equals(z) == true

  四、一致性:屡次调用equals返回结果相同

  (null与任何对象比较都应该返回false)

 

相关文章
相关标签/搜索