1. 程式人生 > 實用技巧 >java identityHashCode 和 hashCode

java identityHashCode 和 hashCode

當類並沒有重寫Object#hashCode()時, 對於 System.identityHashCode(Object) 和 Object#hashCode() 的結果是一致的;

但對於類似String這些重寫了Object#hashCode()的類時,當直接呼叫hashCode()時,由於過載的存在,因此呼叫的是子類中的方法;

對於這種情況,當我們需要獲取物件的hashCode時

  1. 方法一:我們可以使用System.identityHashCode(Object) 來直接獲取物件的hashCode
  2. 方法二:可以通過MethodHandle 來呼叫被子類過載的父級的方法
 public void identityHashCodeVsHashCode() throws Throwable {
        Object o = new Object();
        // 對於Object物件 而言;System.identityHashCode 和 Object#hashCode是相同的
        assert System.identityHashCode(o) == o.hashCode();
        // 對於 s1 和 s2 實際都是引用的 META區域中相同的物件
        String s1 = "1";
        String s2 = "1";
        assert System.identityHashCode(s1) == System.identityHashCode(s2);

        String s3 = new String("1");
        assert s1.hashCode() == s3.hashCode();
        // 對於s1 和 s3 實際是兩個不同的物件, 但由於 String重寫了Object#hashCode()
        // 當需要對比物件時,我們並不能直接呼叫到Object#hashCode(),因此只能通過System.identityHashCode來獲取物件的hashcode
        assert System.identityHashCode(s1) != System.identityHashCode(s3);
        // 獲取指定類的構造方法並執行
        Object object = MethodHandles.lookup().findConstructor(Object.class, MethodType.methodType(void.class)).invoke();
        // 獲取指定類的方法並繫結指定的物件
        MethodHandle methodHandle = MethodHandles.lookup().findVirtual(Object.class, "hashCode", MethodType.methodType(int.class)).bindTo(s3);
        Object invoke = methodHandle.invoke();
        System.out.println((int)invoke);
        assert (int)invoke == System.identityHashCode(s3);
    }