【问题标题】:Do final fields initialized outside of constructors get initialized before running the constructor? [duplicate]在构造函数之外初始化的最终字段是否在运行构造函数之前被初始化? [复制]
【发布时间】:2018-02-07 07:53:22
【问题描述】:

假设你有这个代码sn-p

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。

那么问题又来了,这种重新排序可能吗?或者在构造函数之外初始化的所有最终字段是否在构造函数之前初始化,或者至少总是由编译器移动到构造函数的顶部

【问题讨论】:

  • 在运行构造函数之前,它们所属的实例不存在。另外:从构造函数调用非最终(可能通过继承更改)方法并不是最明智的做法。

标签: java multithreading thread-safety visibility safe-publication


【解决方案1】:

final 字段不可能。

看看The Java ® Language Specification Java SE 8 Edition > 17.5.2 Reading final Fields During Construction:

17.5.2 在构造过程中读取 final 字段

在构造该对象的线程中读取对象的最终字段是 根据构造函数中该字段的初始化排序 通常发生在规则之前。如果在构造函数中设置字段之后发生读取, 它会看到最终字段分配的值,否则它会看到默认值。

但是您也可以看到,它不能保证后续使用反射的final 字段修改。详情请见17.5.3

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-14
    • 1970-01-01
    • 2018-08-02
    • 2015-02-08
    相关资源
    最近更新 更多