Java实例化
问题内容:
- 当用Java实例化一个对象时,真正进入内存的是什么?
- 是否包含父级构造函数的副本?
- 投射时,为什么隐藏数据成员的行为与重写方法不同?
我理解为使您正确使用这些东西而通常给出的抽象解释,但是JVM如何真正做到这一点。
问题答案:
实例化对象时,实际上仅“静态”数据以及创建该对象的对象类型的引用被“创建”。
没有方法被复制过。
创建它的类的“引用”实际上是一个指针调度表。该类可用的每个方法都存在一个指针。指针始终指向该方法的“正确”(通常是对象树中最低/最具体)的实现。
这样,如果您对另一个方法进行了顶层调用,但另一个方法已被覆盖,则将调用被覆盖的方法,因为这是表中指针所指向的位置。由于这种机制,调用覆盖方法应该比顶层方法花费更多时间。
指针表+成员变量是类的“实例”。
变量问题与完全不同的机制“名称空间”有关。变量根本不属于“子类”(它们不进入分配表),但是公共变量或受保护变量可以被局部变量隐藏。这些都是由编译器在编译时完成的,与您的运行时对象实例无关。编译器确定您真正想要的对象,并将对该对象的引用填充到您的代码中。
作用域规则通常倾向于“最近”变量。具有较远名称的任何内容都将被忽略(阴影),以支持更近的定义。
如果您感兴趣的话,可以更详细地了解内存分配:所有“对象”都分配在“堆”上(实际上,它比真正的堆更有效,更漂亮,但概念相同。)变量始终是指针-
Java永远不会复制对象,您总是将指针复制到该对象。方法参数和局部变量的变量指针分配是在堆栈上完成的,但是即使变量(指针)是在堆栈上创建的,它们指向的对象仍然永远不会在堆栈上分配。
我很想写一个例子,但这已经太久了。如果您要我输入具有扩展关系的几个类,以及它们的方法和数据如何影响生成的代码,我可以…问。