String 与其他 class 对象的 hashCode

The hashCode for String versus other class objects

class Employee {
  String name;

  Employee(String name) {
    this.name = name;
  }
  // hashCode method is not overridden
}

public class HashCodeConfusion {
  public static void main(String[] args) {
    Employee emp = new Employee("ABC");
    Employee emp1 = new Employee("ABC");

    if (emp == emp1) {
      System.out.println("Employee Same reference");
    } else {
      System.out.println("Employee Different reference");
    }
    if (emp.hashCode() == emp1.hashCode()) {
      System.out.println("Employee Same hash code");
    } else {
      System.out.println("Employee Different hash code");
    }

    // -----------------------------------

    String str = new String("ABC");
    String str1 = new String("ABC");

    if (str == str1) {
      System.out.println("String Same reference");
    } else {
      System.out.println("String Different reference");
    }
    if (str.hashCode() == str1.hashCode()) {
      System.out.println("String Same hash code");
    } else {
      System.out.println("String Different hash code");
    }
  }
}

Question/Confusion: Object class 的默认 hashCode 似乎考虑了对象引用而不仅仅是内容,否则为什么同名的 employee class 对象会出现不同的哈希码? 如果 Object class 的默认实现有一些仅基于内容的哈希算法,那么只要我的 equals 范式同意按位兼容性,就不需要重写 hashCode 方法。

有什么可以消除这种困惑的吗?

默认的 hashCode() 不基于参考,也不基于系统中的任何地址。它是一个随机生成的数字,存储在 header 中。它这样做是为了在不更改 hashCode() 的情况下移动 object,并且 hashCode 是相当随机的。

注:

  • 次要 GC 后,eden space 为空,创建的第一个 object 始终位于同一地址。它没有相同的 hashCode。
  • object默认创建在8字节边界上,因此低三位可以全为000,这对hashCode没有用。如果您使用 Compressed Oops,低位可能不会被存储,但仍然不是很随机。
  • 使用Unsafe您可以读取甚至覆盖存储的哈希码。在 OracleJVM/OpenJDK 上,hashCode 存储在 object.
  • 开头的 1 个字节处
  • 用于存储hashCode的位也用于baised locking。一旦你获得了 object 的内置 hashCode,它就不会使用偏向锁定。
  • 您可以使用 System.identityHashCode(x) 获取任何 object 的系统 hashCode,这正是 IdentityMap 使用的。