好问题。您正在探索的是 Java 如何初始化对象- 并且涉及到许多步骤。
我知道构造函数也是一种方法(也许我错了)。
几乎正确。构造函数是一种特殊的方法。如果你反编译一个类文件,你会看到构造函数被重命名为<init>
. <init>
与其他方法不同,例如,不能显式调用,除非使用关键字new
or super
。这是非常基础的,以至于它是在 JVM 本身中实现的,而不是在 Java 语言中定义的东西。
在这种情况下创建了多少个 Object。
创建了一个对象 - 的一个实例C
。
C
是另外且同时是 的一个实例B
和 的一个实例A
和 也Object
.
如果创建了一个对象,那么在内部如何super()
调用 Parent 类 Constructor 。Super 是如何调用父类构造函数的。
这是我们进入初始化的地方——初始化是JVM如何创建一个对象的新实例并设置所有成员值——特定类的成员值和超类的成员值。涉及几个阶段:
- 加载所有引用的类并初始化这些类。类初始化本身并不重要,所以我不会在这里介绍它。非常值得一读。
- 分配一块内存来保存实例的成员,其中将包括 和 的
A
所有B
成员C
。注意,这解释了您问题的一个方面:基类及其子类的构造函数如何更新或引用同一个对象 -所有类的实例的所有成员一个接一个地存储在同一块内存中。
- 将所有成员初始化为其默认值。例如,
int
和float
成员将被设置为 0 和 0.0f。
执行或计算成员初始化器,例如:
private int a = 10;
private int b = a * 5;
private String c = Singleton.getInstance().getValue();
注意 (1) 成员初始化严格按照在类中声明成员的顺序进行。这意味着声明中稍后对成员的引用被破坏:
private int a = b * 5; // Forward reference; won't compile
private int b = 10;
注意 (2) 在 Java 中有一个未充分使用的工具来运行任意代码以在执行构造函数之前初始化值。这些代码块此时再次严格按照声明顺序执行:
private int a;
private int b = 1;
{
// Initization occurs after b but before c.
// c cannot be referenced here at all
int i = SomeClass.getSomeStatic();
a = i * 2;
}
private int c = 99;
执行 的构造函数C
。构造函数必须直接从超类调用构造函数,否则编译器将自动添加super()
为构造函数的第一行。这意味着构造函数严格按顺序执行:
Object
A
B
C
该对象现在已初始化并可以使用。如果您使用实例方法初始化值,您可能会做一些危险的事情:
public class Wrong {
int a = getB(); // Don't do this!
int b = 10;
public int getB() {
return b;
}
}
在这里,a
被初始化为0
。这是因为,在getB()
调用点时,Java 已将 的值清除为b
默认值 ( 0
),但尚未10
在初始化的第二阶段将其设置为。
总之 - 只有一个对象,它是分阶段创建和初始化的。在这些阶段中,根据定义,对象并未完全定义。