好问题。您正在探索的是Java如何初始化对象 - 并且涉及许多步骤。
我知道是构造函数也是一种方法(也许我错了)。
几乎正确。构造函数是一种特殊方法。如果反编译类文件,您将看到构造函数重命名为 。 与其他方法的处理方式不同,例如,除非通过使用关键字 或 ,否则无法显式调用。这是如此重要,以至于它是在JVM本身中实现的,而不是在Java语言中定义的东西。<init>
<init>
new
super
在这种情况下,创建了多少个对象。
将创建一个对象 - 的实例。C
C
另外,同时是 的实例和 的实例,也是 的实例。B
A
Object
如果创建了一个对象,则在内部调用父类构造函数的方式。Super 如何能够调用父类构造函数。super()
这就是我们进入初始化的地方 - 初始化是JVM如何创建对象的新实例并设置所有成员值 - 特定类和超类的成员值。涉及几个阶段:
- 加载所有引用的类并初始化这些类。类初始化本身就不是微不足道的,所以我不会在这里介绍它。这是非常值得一读的。
- 分配一个内存块用于保存实例的成员,该内存块将包括 和 的所有成员。注意,这解释了您的问题的一个方面:基类及其子类的构造函数如何更新或引用同一对象 - 来自所有类的实例的所有成员都一个接一个地存储在同一个内存块中。
A
B
C
- 将所有成员初始化为其默认值。例如,和成员将设置为 0 和 0.0f。
int
float
-
执行或计算成员初始值设定项,例如:
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;
}
}
此处,初始化为 。这是因为,在调用时,Java 已将 的值清除为缺省值 (),但在初始化的第二阶段尚未将其设置为 。a
0
getB()
b
0
10
总而言之 - 只有一个对象,它分阶段在一个数字中创建和初始化。在这些阶段,根据定义,对象不是完全定义的。