在 class 级别初始化 属性 将在加载或构造函数期间分配内存?
Initialize the property at class level will allocate memory during load or constructor?
我们有 class 比方说 AnimalShelter,它有一个动物列表。当我们在 class 级别初始化它时,它会在加载 class 期间或在创建对象期间创建内存。
class Animal{
String name;
}
class AnimalShelter{
private List<Animal> animals = new ArrayList<>();
}
我的理解是它会在内存加载期间初始化 属性 或者当我们构造一个对象时它会创建一个带有新列表的对象。一个初始化总是在 class 级别。
如果我们在构造函数中初始化列表,它只有一个引用,当我们创建一个对象时会分配内存。 class 级别
没有内存分配
class AnimalShelter{
private List<Animal> animals;
AnimalShelter(){
animals = new ArrayList<>();
}
}
我们如何验证这个东西或者我对这个理解完全错误?
根据JLS 16第12.5节创建新Class实例,创建实例后,顺序为:
- 将构造函数的参数分配给新创建的参数变量
对于此构造函数调用。
- 如果此构造函数以显式构造函数调用开始
同一个 class 中的另一个构造函数(使用 this),然后计算参数
并使用这五个递归地处理构造函数调用
脚步。如果该构造函数调用突然完成,则此过程
出于同样的原因突然完成;否则,继续第 5 步。
- 此构造函数不是以显式构造函数调用开始的
同一个 class 中的另一个构造函数(使用 this)。如果此构造函数用于
class 而非 Object,则此构造函数将以显式开头
或隐式调用 superclass 构造函数(使用 super)。评估
递归使用 superclass 构造函数调用的参数和过程
同样的五个步骤。如果该构造函数调用突然完成,则
出于同样的原因,此过程突然完成。否则,继续
与步骤 4.
- 为此class执行实例初始化器和实例变量初始化器,
将实例变量初始化器的值分配给相应的
实例变量,按照它们在文本中出现的从左到右的顺序
class 的源代码。如果执行这些初始化程序中的任何一个结果
在异常中,则不会处理进一步的初始值设定项,并且此过程
以相同的异常突然完成。否则,继续第 5 步。
- 执行此构造函数主体的其余部分。如果该执行完成
突然,然后这个过程出于同样的原因突然完成。
否则,此过程正常完成。
例如,下面将依次打印A、B、C、D、E。请注意,虽然 C 块在源代码中 after 构造函数,但它在 before 执行,因为实例初始化器都被执行 在构造函数之前。
public class Test {
{
System.out.println("A");
}
Sub sub = new Sub();
public Test() {
System.out.println("D");
}
{
System.out.println("C");
}
public static void main(String[] args) {
var test = new Test();
System.out.println("E");
}
}
class Sub {
public Sub() {
System.out.println("B");
}
}
我们有 class 比方说 AnimalShelter,它有一个动物列表。当我们在 class 级别初始化它时,它会在加载 class 期间或在创建对象期间创建内存。
class Animal{
String name;
}
class AnimalShelter{
private List<Animal> animals = new ArrayList<>();
}
我的理解是它会在内存加载期间初始化 属性 或者当我们构造一个对象时它会创建一个带有新列表的对象。一个初始化总是在 class 级别。
如果我们在构造函数中初始化列表,它只有一个引用,当我们创建一个对象时会分配内存。 class 级别
没有内存分配class AnimalShelter{
private List<Animal> animals;
AnimalShelter(){
animals = new ArrayList<>();
}
}
我们如何验证这个东西或者我对这个理解完全错误?
根据JLS 16第12.5节创建新Class实例,创建实例后,顺序为:
- 将构造函数的参数分配给新创建的参数变量 对于此构造函数调用。
- 如果此构造函数以显式构造函数调用开始 同一个 class 中的另一个构造函数(使用 this),然后计算参数 并使用这五个递归地处理构造函数调用 脚步。如果该构造函数调用突然完成,则此过程 出于同样的原因突然完成;否则,继续第 5 步。
- 此构造函数不是以显式构造函数调用开始的 同一个 class 中的另一个构造函数(使用 this)。如果此构造函数用于 class 而非 Object,则此构造函数将以显式开头 或隐式调用 superclass 构造函数(使用 super)。评估 递归使用 superclass 构造函数调用的参数和过程 同样的五个步骤。如果该构造函数调用突然完成,则 出于同样的原因,此过程突然完成。否则,继续 与步骤 4.
- 为此class执行实例初始化器和实例变量初始化器, 将实例变量初始化器的值分配给相应的 实例变量,按照它们在文本中出现的从左到右的顺序 class 的源代码。如果执行这些初始化程序中的任何一个结果 在异常中,则不会处理进一步的初始值设定项,并且此过程 以相同的异常突然完成。否则,继续第 5 步。
- 执行此构造函数主体的其余部分。如果该执行完成 突然,然后这个过程出于同样的原因突然完成。 否则,此过程正常完成。
例如,下面将依次打印A、B、C、D、E。请注意,虽然 C 块在源代码中 after 构造函数,但它在 before 执行,因为实例初始化器都被执行 在构造函数之前。
public class Test {
{
System.out.println("A");
}
Sub sub = new Sub();
public Test() {
System.out.println("D");
}
{
System.out.println("C");
}
public static void main(String[] args) {
var test = new Test();
System.out.println("E");
}
}
class Sub {
public Sub() {
System.out.println("B");
}
}