Java 个对象的默认 hashCode() 实现

Default hashCode() implementation for Java Objects

我试图理解 Java 对象的 hashCode() 并看到以下 Java 对象的 hashCode() 方法的代码:

package java.lang;
public class Object {

 // Some more code

 public native int hashCode();

 // Some other code

}

现在,我们知道如果我们创建一个 class 它会隐式扩展对象 class,为此我写了一个示例:

package com.example.entity;
public class FirstClass {
    private int id;
    private String name;
    // getters and setters
}

因此,这个 class 即:FirstClass 将隐式扩展 Object class。

主要class:

package com.example.app.main;
import com.example.entity.FirstClass;
    public class MainApp {
        public static void main(String[] args) {
             FirstClass fs = new FirstClass();
             fs.setId(1);
             fs.setName("TEST");
             System.out.println("The hasCode for object fs is " + fs.hashCode());
         }
 }

由于 FirstClass 隐含地扩展了 Object class,因此它将具有 Object classes' hashCode() 方法。

我在 FirstClass 对象上调用了 hashCode(),并且由于我没有覆盖 hashCode(),理论上它应该调用 Object class的 hashCode().

我的疑问是:

由于对象 class 没有任何实现,它如何计算任何对象的哈希码?

在我的例子中,当我 运行 程序时,它返回的哈希码是 366712642。

谁能帮我理解一下?

你弄错了:

public native int hashCode();

并不意味着没有实现。这只是意味着该方法是在 JVM 的 native 又名 C/C++ 部分中实现的。这意味着您找不到该方法的 Java 源代码 代码。但是在 JVM 中的某个地方仍然有一些代码会在您对某个对象调用 hashCode() 时被调用。

正如另一个答案所解释的那样:"default" 实现使用了基础对象的 "memory" 地址。事情是:使用 java 意味着,没有 "memory addresses" 的知识。请记住:JVM 是用 C/C++ 编写的 - real 内存管理发生在 JVM 的这些 native 部分.

换句话说:您不能编写 Java 代码来告诉您对象的 "native memory address"。

但正如 Eugene 的另一个回答所表明的那样:关于 "memory location" 的散列已成为过去。

对象中Hashcode的默认实现class是对象的十六进制内存地址。 JVM 调用此实现。

一些有用的链接是:

https://docs.oracle.com/javase/tutorial/java/IandI/objectclass.html https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html

尽管这里有一些答案指出默认实现是基于 "memory" 的,但这显然是错误的。现在很多年都不是这样了。

在java-8下,你可以这样做:

java -XX:+PrintFlagsFinal | grep hashCode

获取使用的确切算法(5 是默认值)。

  0 == Lehmer random number generator, 
  1 == "somehow" based on memory address
  2 ==  always 1
  3 ==  increment counter 
  4 == memory based again ("somehow")
  5 == read below

默认(5),使用的是Marsaglia XOR-Shift算法,与内存无关

这不是很难证明,如果你这样做:

 System.out.println(new Object().hashCode());

多次,始终在新的 VM 中 - 您将获得相同的值,因此 Marsaglia XOR-Shift 从种子开始(总是相同,除非其他代码不改变它)并且有效从那个。

但是即使你切换到一些基于内存的 hashCode,并且 Objects 可能会四处移动(垃圾收集器调用),你如何确保在 之后采用相同的 hashCode GC 移动了这个 object?提示:indentityHashCode 和 Object headers。