问题描述
《 Core Java Volume I》一书中的一个例子
super
super
将导致ArrayStoreException,因为该数组存储了错误的对象。
我给出了数组的内存图:
我认为变量public class Employee {
...
}
public class Manager extends Employee {
...
}
Manager[] managers = new Manager[3];
Employee[] staff = managers; //OK
staff[0] = new Employee(); //error
存储staff [0]的地址(就像c ++,在staff[0]
中,变量staff
存储数组的第一个元素的地址)。
因为int *p = new int[3]
等于p
,所以它们指向相同的内存位置,所以当您编写语句staff
时,我认为它等于语句{{1 }},对父项的引用指向子对象是错误的。
我不确定我是否正确,我希望知道对数组的引用(工作人员/经理)与各个数组元素(managers
,staff[0] = new Employee()
... ),managers[0] = new Employee()
是否可以告诉我数组中第一个元素在内存中的位置。
我还想知道,对于staff[0]
和staff[1]
这样的不同对象数组,它们是否占用相同的内存大小。对不同对象的引用占用相同的内存量吗?
解决方法
我希望了解对数组(职员/经理)的引用与各个数组元素(
staff[0]
,staff[1]
...)之间的关系,staff
是否可以告诉我数组中第一个元素在内存中的位置。
在Java中,单个数组元素是数组对象中的变量,如section 10 in the language specification中所述。在语言级别上,没有内存地址或指针算术。该语言不会告诉您staff[0]
和staff[1]
和staff
的内存地址之间是否存在任何关系-取决于实现。
关于实现的工作方式,来自AlekseyShipilёv(JOL的原始作者)的这篇文章非常有用:https://shipilev.net/jvm/objects-inside-out/
总而言之,数组对象的内存布局包括一个指向对象类的指针,一个有助于垃圾回收和并发的“标记词”,数组的长度(项目数),以及数组元素本身。
由于有“对象标头”,因此工作人员[0]与工作人员的地址不同。但是区别是JVM知道一个数字,因此它可以生成使用航位推算来访问数组元素的高效代码。
关于如何抛出ArrayStoreException
:创建new Manager[3]
之类的对象数组时,JVM设置类指针,以便它引用“管理器数组”类(如果(尚不存在,而是动态创建的)。当您存储对数组的对象引用时,JVM使用此类指针检查引用是否与数组组件类型兼容,如果不兼容则抛出ArrayStoreException
。