java identityHashCode 和 hashCode
阅读原文时间:2023年07月10日阅读:2

当类并没有重写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);  

    }