当前位置: 首页 > 面试题库 >

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

佘缪文
2023-03-14
问题内容
Animal myAnimal = new Animal();

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

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

我不明白的是

  1. 内存地址值看起来如何?
  2. 是一个地址还是多个地址值?如果只有一个,myAnimal如何访问动物对象的所有对象字段,例如myAnimal.name,myAnimal.height,…?

谁能解释一下?提前致谢。


问题答案:

Java虚拟机规范状态

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

并澄清

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

所以变量myAnimal

Animal myAnimal = new Animal();

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

你问

内存地址值看起来如何?

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

对象本身不仅仅是其地址。实际上,随着垃圾回收器移动对象,其地址在JVM进程的整个生命周期中可能会多次更改。

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

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

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

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

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

该字段name是type
String,是引用类型,我们基本上只知道存储一个指针。如果我们假设JVM仅需要32位来存储指针,那么我们知道该字段仅需要32位。

该字段height的类型byte为,仅指定为8位。

因此,每个Person对象实际上只需要32+85位字节的数据即可。JVM很可能会为其内部组织分配更多的资源,但让我们简化为这5个字节。在您的示例中,JVM将为分配前4个字节,为分配name下一个字节age。就像是

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

你问

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

myAnimal 仅包含一个地址,但类似

myAnimal.height

可以认为height是从内存中读取1字节(因为我们知道是字节类型),该地址是通过将存入的值加4(因为的数据位置height需要减去所需的4个字节name)而确定的myAnimal

考虑myAnimal存储指向的内存地址的指针,该指针的12初始化是name指向内存地址处的String
1345height值为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



 类似资料:
  • 问题内容: 我有一个main.go文件,其中有: 在我要声明,可在我的应用程序的任何地方访问的全局变量。有可能吗?我试过了: 但是,即使在同一包中,我也无法访问变量。 问题答案: 在顶层声明变量-在任何函数之外: 由于变量的名称以大写字母开头,因此在导入定义变量的包并使用包名对其进行限定时,变量将在当前包中通过其名称可用-在任何其他包中都可用。 这是另一个示例(同样在Go游乐场中:https :

  • }; 因此,我创建了一个对象变量“stock”。包含不同产品的代码、名称、成本和数量。 后来,我创建了一个函数“viewAllStock()”来在我的网站(超文本标记语言)中创建一个表。但是当我运行这个程序时,我在我创建的“产品代码”单元格下得到它 产品代码 [对象对象] [对象对象] [对象对象] [对象对象] [对象对象] 那么,如何使用Javascript在网站(超文本标记语言)中获取标题“

  • 问题内容: 为什么我们可以通过Java中的对象引用访问静态变量,如下面的代码? 问题答案: 通常,每个人都可以访问公共变量,并且只能从该类的当前实例内部访问私有变量。在您的示例中,您被允许从方法中访问变量,因为该方法在Static类内。 如果您想知道为什么为什么要允许您从静态类的另一个实例(而不是当前实例)访问它(通常不允许使用私有变量),这仅仅是因为静态变量不存在于静态类中。每个实例,但每个班级

  • 问题内容: 编写以下代码时,编译器如何不抱怨? 即使它是在其中编写的同一类的实例,也不应该在处给出编译错误吗?毕竟,我试图直接访问一个私有变量。 该代码甚至可以正常运行。 问题答案: 私有成员可以从声明它的类中的任何方法访问,无论该方法是访问其自己的()实例的私有成员还是访问其他实例的私有成员。 JLS 6.6.1中 对此进行了说明: …否则,如果将成员或构造函数声明为私有,则仅当访问发生在封装成

  • 问题内容: 是否有可能在Java中获得对对象的所有引用。 我需要检查的是对象是否删除了所有的回调订阅。 谢谢 问题答案: 这可以通过JVMTI实现,并且通常由堆分析器完成。但是,它不能在Java内部完成。

  • 我正在尝试使用动态名称访问对象的属性。这可能吗?