单个引用变量如何访问所有对象字段?

Animal myAnimal = new Animal(); 

我上面有这个代码。 据我所知,它会做这些事情:

  1. 将在堆内存上创建动物对象
  2. 对该对象的引用将传递给引用变量“myAnimal”。换句话说,“myAnimal”变量保存堆上“Animal”对象的内存地址。

我不明白的是

  1. 内存地址值如何?
  2. 这是一个地址还是众多地址值? 如果只有一个,myAnimal如何访问Animal对象的所有对象字段,如myAnimal.name,myAnimal.height,……?

有人能解释一下吗? 提前致谢。

Java虚拟机规范说明

有三种引用类型:类类型,数组类型和接口类型。 它们的值分别是对动态创建的类实例,数组或类实例或实现接口的数组的引用。

并澄清

类型引用的值可以被认为是指向对象的指针

所以变量myAnimal in

 Animal myAnimal = new Animal(); 

正在堆上存储指向Animal对象的指针。

你问

内存地址值如何?

内存地址通常只是一个数值,它是进程’已分配内存的偏移量。 当进程读取该值时,它可以直接寻址该位置并从中读取或写入(将其视为数组中的偏移索引)。

对象本身不仅仅是它的地址。 实际上,当垃圾收集器移动对象时,它的地址可以在JVM进程的生命周期内多次更改。

但是, JVMS不指定对象的内部结构。

Java虚拟机不要求对象的任何特定内部结构。

在Oracle的一些Java虚拟机实现中,对类实例的引用是指向句柄的指针,该句柄本身是一对指针:一个指向包含对象方法的表和指向表示Class对象的指针对象的类型,另一个是从堆中为对象数据分配的内存。

这没有太大帮助,但是我们可以假设为对象数据分配的内存必须足够大以包含所有对象的字段,并且数据需要快速访问,即。 在恒定的时间内,而不是与数据量成比例。 典型的解决方案是再次使用偏移。 以这门课为例

 class Animal { private String name; private byte height; } 

字段nameString类型,一种引用类型,我们知道它实际上只存储一个指针。 如果我们假设我们的JVM只需要32位来存储指针,我们知道这个字段只需要32位。

字段heightbyte类型,指定只需要8位。

所以每个Person对象实际上只需要32+8位,其数据为5个字节。 JVM最有可能为其内部组织分配更多,但让我们简化为这5个字节。 在您的示例中,JVM将为名称分配前4个字节,为该age分配下一个字节。 就像是

  0 8 16 24 32 40 +--------+--------+--------+--------+--------+ | name | height | 

你问

这是一个地址还是众多地址值? 如果只有一个,myAnimal如何访问Animal对象的所有对象字段,如myAnimal.name,myAnimal.height,……?

myAnimal只保存一个地址,但表达式如下

 myAnimal.height 

可以被认为是从存储器读取1个字节(因为我们知道height是字节类型),该地址通过将存储的值加4(因为height数据的位置偏移了4个字节所确定)确定的地址在myAnimal

考虑myAnimal存储指向内存地址为12的指针,使用指向内存地址为1345的字符串的name初始化, height值为6.在内存中,可能看起来像

  myAnimal | v Heap: ...12.......13.......14.......15.......16.......17 Object offsets: ....0 1 2 3 4 5 ....+--------+--------+--------+--------+--------+ | 1345 | 6 | 

要读取myAnimal.height ,JVM将计算12 + 4 = 16并读取该偏移处的字节( 6 )。 要为myAnimal.name分配新值,JVM将计算12 + 0 ,并写入4个字节,表示一些新的指针值,覆盖1345

这是过于简单化:

  1. 它只是一个代表某个地址位置的数字; 这个数字有多大取决于您的计算机架构(32位或64位)

  2. 这是一个地址值; 它是内存中对象表示开始的地方的地址位置。

您可以将其与您房屋的地址进行比较。 它有一个地址。 您家(场)中的所有房间都有不同的位置,但您必须通过前门(“开始”位置)进入。 房间位置相对于您的前门。 我承认这个例子有点做作,但你明白了……

地址只是一个long数字来表示对象的内存位置。 它们取决于机器的位数。 它在64位机器上是64位长,在32位机器上是32位长。

内存地址值如何?

如果您真的热衷于在控制台中查看这些大数字,那么您可以实际探索Unsafe API

 public native long getAddress(long address) 

从给定的内存地址获取本机指针。 如果地址为零,或者未指向从#allocateMemory获取的块,则结果是未定义的。

如果本机指针的宽度小于64位,则将其作为无符号数扩展为Java long。 指针可以由任何给定的字节偏移量索引,简单地通过将该偏移量(作为简单整数)添加到表示指针的长度。 实际从目标地址读取的字节数可以通过咨询#addressSize来确定。


这是一个地址还是众多地址值? 如果只有一个,myAnimal如何访问Animal对象的所有对象字段,如myAnimal.name,myAnimal.height,……?

那么它应该是顶级的一个 ,地址位置可能包含其他人的地址位置(我不是很确定)

我还没有尝试在我的机器上运行它。

创建对象时,java不会使用reference variable共享其Actual Memory Address ,而不是Java为object创建index number ,该index number将传递给该对象的reference variable 。 因此,您可以借助该index number访问您的对象。 此外,您的对象保留其childrenrefrences并帮助您访问它们。