在构造函数之外初始化的最终字段是否在 运行 构造函数之前初始化?
Do final fields initialized outside of constructors get initialized before running the constructor?
假设你有这段代码
private final Set set = new HashSet() {{ add(1); }};
SomeConstructor() {
printSet();
}
long printSet() {
new Thread(() -> {System.out.println(set)}).start();
}
例如,如果编译器决定让它看起来像
private final Set set;
SomeConstructor() {
printSet();
set = new HashSet() {{ add(1); }};
}
这会是个问题,因为 calculateWaitTime() 生成的新线程可能会将集合视为 null 或其中没有 1。
那么问题又来了,这个重新排序可以吗?还是在构造函数之外初始化的所有最终字段都在构造函数之前初始化,或者至少总是由编译器移动到构造函数的顶部
final
字段不可能。
17.5.2 Reading final Fields During Construction
A read of a final field of an object within the thread that constructs that object is
ordered with respect to the initialization of that field within the constructor by the
usual happens-before rules. If the read occurs after the field is set in the constructor,
it sees the value the final field is assigned, otherwise it sees the default value.
但是正如您也看到的那样,对于使用反射进行的后续 final
字段修改并不能保证。有关详细信息,请参阅 17.5.3。
假设你有这段代码
private final Set set = new HashSet() {{ add(1); }};
SomeConstructor() {
printSet();
}
long printSet() {
new Thread(() -> {System.out.println(set)}).start();
}
例如,如果编译器决定让它看起来像
private final Set set;
SomeConstructor() {
printSet();
set = new HashSet() {{ add(1); }};
}
这会是个问题,因为 calculateWaitTime() 生成的新线程可能会将集合视为 null 或其中没有 1。
那么问题又来了,这个重新排序可以吗?还是在构造函数之外初始化的所有最终字段都在构造函数之前初始化,或者至少总是由编译器移动到构造函数的顶部
final
字段不可能。
17.5.2 Reading final Fields During Construction
A read of a final field of an object within the thread that constructs that object is ordered with respect to the initialization of that field within the constructor by the usual happens-before rules. If the read occurs after the field is set in the constructor, it sees the value the final field is assigned, otherwise it sees the default value.
但是正如您也看到的那样,对于使用反射进行的后续 final
字段修改并不能保证。有关详细信息,请参阅 17.5.3。