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。
我试图理解 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。