Java中的句柄概念是什么?

4
我在一个网站上读到(http://www.rajeshpatkar.com/articles/javarefpnt/),当我们实例化一个类时,也就是创建一个对象时,Java会在内存中为该对象分配空间。
Emp e = new Emp();

变量e中存储了一个句柄,它不是指针,即它不存储内存中对象的地址。
该说明给出了指针数组的示例。内存地址存储在a[1]位置,当对象移动时,此位置将更新为新地址。
那么为什么要使用这个数组,而不是直接存储地址(它指出这有助于GC,但我没有理解),并在对象移动时更新存储在e中的地址?
我花了很多时间来理解这个问题,但仍然没有找到令我满意的答案。如果您可以用一个例子来解释变量'e'实际上存储了什么,那就太棒了。
谢谢 :)
2个回答

10

通常术语是“对象引用”(或仅称为“引用”),而不是“句柄”。

对象引用是一个不透明的值,它唯一地标识了某个对象对于JVM。该值的形式未被规范定义。我怀疑它通常是int或long类型的大小,但我认为即使这些也没有被JLSJVM规范涵盖。(让你有一个想法,JVM规范明确指出,甚至null(表示“无引用”的特殊值)的确切值也没有被规定。)

引用不是指针,尽管当然,由于引用的形式未指定,因此使用指针作为引用实现JVM是可能的,只要不能以违反规范的方式利用该事实。

因为引用不是指针,所以Java没有像C及其相关语言那样的“指针算术”。

如果你能举个例子来解释一下变量'e'实际上存储了什么,那会很有帮助。这并没有被规范定义。它只是一个唯一标识对象的值(我们永远看不到这个值;当你使用System.out打印一个没有实现toString方法的对象时,你看到的十六进制值只是一个神话,它并不是对象的引用)。如何标识该对象取决于JVM的实现。它可以是一个指针,也可以是一个指针数组的索引,还可以更复杂,使用不同位从参考值中获取不同的信息。

很好的解释,伙计。我终于理解了句柄的概念。继续以指针数组为例,即'e'(引用变量)指向a[1],而a[1]又存储对象的地址。进一步了解到,在Java中我们无法更改'e'的值,即我们无法使'e'指向a[5]或Java中的任何其他内存,只能更改内容,即在a[1]处存储的值。这在Java中的原因是什么?允许它可能会带来哪些风险? - Jayesh Saita
2
@JayeshSaita:很高兴能帮到你。“...后来我知道我们不能改变'e'的值...” 是的,我们可以:e = someOtherObject; 不要被JVM可能如何实现它所困扰。只需记住:变量存储值。引用类型变量中存储的值是对象引用。该值告诉JVM对象在哪里。 :-) - T.J. Crowder

1

一个句柄存储在变量e中,它不是指针,即它不存储内存中对象的地址。

在所有实际目的下,您可以假设它存储了对象在内存中的地址。

然而,请考虑在Java中,您无法以显式方式管理内存。这意味着您不能使此类变量指向内存中的特定位置。您只能将这些变量指向特定实例。


除了压缩的oops之外,“在所有实际目的上……”- https://dev59.com/gl8f5IYBdhLWcg3wB-wU - Stephen C
在64位JVM的情况下,为真。 - Andres
我认为这在实际应用中并不起作用。通常情况下,可以通过hashcode()实现(尽管这不是必需的),将对象引用转换为整数,对吧?如果它依靠内存中的指针,那么每次垃圾回收移动该实例时都会使其返回不同的hashcode,即使对象没有发生改变。这违反了hashcode()的契约。 - Maksim Gumerov

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