Java的new操作符和hashcode()方法

3
首先,我要谈的是默认的hashCode()方法,而不是被覆盖的方法。当我们创建一个新对象时,“new”操作符返回该对象创建的内存地址;在 Java 中我们通常称其为引用。我想知道的是,这是否与hashCode()返回的值相同?
我认为它们是相同的。但是,当我们拥有超过2^32个对象并且给定hashCode()返回一个整数(2^32个不同的数字)时,会出现大量碰撞,当我们传递对象时,将会是一团糟。JVM如何处理这种情况?
5个回答

5
当我们创建一个新对象时,“new”操作符返回它创建的对象的内存地址,通常在Java中我们称之为返回引用。
好的,引用并不一定是一个地址。它是指向对象的一种方式-位值的精确值取决于JVM实现。
我想知道的是,这是否与hashCode()返回的值相同?
不一定。您绝对不应该在这方面做出任何假设。同样,这是一个实现细节。
值得记住的是,尽管垃圾收集器可以在内存中移动对象(随着引用的更新),但哈希码不能基于此更改,这是反对您建议的一个论据。
但是,当我们拥有超过2^32个对象,并且给定hashCode()返回整数(2^32个不同的数字)时,将会到处发生碰撞,在传递对象时会变成真正的混乱。
确实会有哈希码碰撞。这是不可避免的-使用哈希码的任何东西都需要考虑到碰撞的可能性。但是引用不能碰撞-能够支持超过2^32个值的JVM显然不能仅仅使哈希码和引用具有相同的值。

当我正在编辑我的帖子,使其更加连贯和可读时,一个新的回答出现了。感谢你节省了我编辑的时间 ;) - Joey
为什么在哈希码的javadoc中会有这种不确定性,比如“尽可能合理地,hashCode方法...”。“尽可能合理”,他们可能是在谈论当存在超过2^32个对象时的情况吗? - samsamara
@user601L:不只是那个原因-可能还有其他原因使得它不切实际。 - Jon Skeet
@user601L:如果已经使用了2^32-1个哈希码,你真的想让JVM花多长时间来寻找最后一个吗?你想让它花费多少内存来保持这个快速呢? - Jon Skeet
谢谢。我还有一个疑问。Java是否通过某种机制来跟踪所有被传递的对象,以避免引用冲突?我的意思是,我们只看到一个值作为对象被传递,但在内部,Java是否做了一些额外的工作,类似于这样的机制? - samsamara
@user601L:对象在堆上的自由空间中创建,只有在垃圾回收的过程中才会移动。我想这样可以很自然地避免冲突。 - Jon Skeet

2
在Java中,我们通常说它返回引用。我想知道的是,这是否与hashCode()方法返回的值相同?
根据Object类中的HashCode方法(我强调的部分):“尽可能合理地,Object类定义的hashCode方法为不同的对象返回不同的整数。(通常通过将对象的内部地址转换为整数来实现,但这种实现技术不是Java编程语言所必需的。) ”所以这对程序员来说是不透明的。 你需要知道的是,通过new操作符,你获取了一个对象的句柄,而hashCode是基于将内部地址转换为表示对象的hashCode的整数的“配方”,无论对象当前位于哪个内存区域(例如由于GC移动)都是相同的。

1

由于哈希码不需要唯一,如果将64位空间中两个对象的地址转换为哈希码冲突,就不会有问题:不同对象的哈希码不需要不同 - 只需要相等对象的哈希码相同。

在现实生活中,TM默认的hashCode值看起来非常类似于对象的地址。然而,这些信息对Java程序员没有用处:即使哈希码等于对象的地址,Java也不提供利用此知识的机制,使其成为无用的实现细节。


现实生活中,为什么要使用TM?只是好奇。 - samsamara
@user601L,由于不同的人对“现实生活”的理解不同,所以“真实生活”并不存在。因此,我的话不应该被过分认真对待,因为它们只是我自己经验的草率概括。 - Sergey Kalinichenko

0
Java中的new不会返回内存地址。更重要的是,Java可以(而且确实会)在内存中重新定位对象。因此,虽然Java中的hashCode()实现可以返回内存地址,但它可能不会这样做,因为它在对象的生命周期内不稳定。 hashCode()不必是唯一的。在将hashCode()用于标识对象的情况下(例如在HashMap中),需要将其与equals()的实现配对以解决冲突。

0
当我们创建一个新对象时,“new”运算符返回该对象的内存地址。
不是的。它返回Java引用。由于垃圾回收和对象可以移动的含义,唯一可以确定的是它不是内存地址。
这与hashCode()返回的值相同吗?
不是的。hashCode不是内存地址,特别是如果已经重写了hashCode()。
我认为它们是相同的。
你的信仰是没有根据的。
但是,当我们拥有超过2^32个对象并且给定hashCode()返回一个整数(2^32个不同的数字)时,将会出现所有的冲突,当我们传递对象时,这将是一个真正的混乱。JVM如何处理?
很明显,你的信仰是错误的。还要考虑64位实现。这里唯一的问题是你的假设。

  1. OP 特别询问了 ObjecthashCode
  2. hashCode 是一个 int,无论 JVM 是 32 位还是 64 位,它始终是一个 32 位的值。
- Cratylus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接