java - 构造函数中的自引用算作 "escaping"吗?

标签 java constructor

阅读 this article关于 JSR-133,它说:

all of the writes to final fields (and to variables reachable indirectly through those final fields) become "frozen," ...

If an object's reference is not allowed to escape during construction, then once a constructor has completed and a thread publishes a reference to an object, that object's final fields are guaranteed to be visible ...

The one caveat with initialization safety is that the object's reference must not "escape" its constructor -- the constructor should not publish, directly or indirectly, a reference to the object being constructed.

我的问题是什么被认为是转义。更具体地说,我想知道这个(有些人为和奇怪的)代码是否会产生一个可安全发布的 Child 对象:

class Parent {
    /** NOT final. */
    private int answer;

    public int getAnswer() {
        return answer;
    }

    public void setAnswer(final int _answer) {
        answer = _answer;
    }
}

public class Child extends Parent {
    private final Object self;

    public Child() {
        super.setAnswer(42);
        self = this;
    }

    @Override
    public void setAnswer(final int _answer) {
        throw new UnsupportedOperationException();
    }
}
  1. 首先,虽然 Parent 显然是可变的,但 Child 是“有效不可变的”,因为允许可变性的父 setter 不再可达。
  2. 构造函数中对“this”的引用对任何人都不可见(不是 getter,也没有传递给任何其他对象)。那么,这算不算“逃跑”?
  3. 但是对象作为一个整体被最终字段(self)引用,所以理论上,它的全部内容应该被“卡住”。 OTOH,最后一个领域本身是不可到达的,所以也许它不算数;我完全可以想象 JIT 会完全优化它。
  4. 如果可以通过 getter 访问“self”,但在构造函数中未调用 getter,那么它是否算作转义(假设之前没有)?这会阻止 JIT 优化它,因此它必须“计数”,也许吧?

那么,Child 是否“可安全发布”,如果不是,为什么,“self”的 getter 会改变答案吗?

如果问题的目的不明确,我认为如果这可行,它可以让一个可变类“安全发布”,只需如上所示扩展即可。

最佳答案

可能误解了转义的含义。关键是 this 的值不能到达构造函数之外的任何代码。我认为一些例子可以更好地解释它:

  • 将私有(private)字段设置为this 不算转义;
  • 调用一个私有(private)方法,而该方法又不调用任何其他方法,也不将 this 分配给外部对象的变量,不算作转义;
  • 调用属于this 的公共(public)、可覆盖方法确实算作转义,除非该类是final。因此,当您调用 setAnswer 时,您的代码会让 this 转义,而不是当您将 this 分配给 self 时。为什么?因为子类可能会覆盖此方法并将 this 发布到任何外部代码。

关于您关于 self 的推理的注释:self 可以从 this 到达,这不取决于外国调用者的事实无法获得它的值(value)。一个方法可以在内部取消引用它就足够了。无论如何,关于卡住的规则没有考虑变量的访问级别。例如,一切都可以通过反射到达。

关于java - 构造函数中的自引用算作 "escaping"吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25555580/

相关文章:

java - 我的服务对象真的属于实体包吗?

java - Eclipse 将数据插入 SQLite 数据库,没有这样的表

java - 重载子类的构造函数

c++ - 为结构类调用构造函数

java - 关于构造函数的困惑

java - Java 中的默认构造函数

java - 在 Java 中使用不带泛型的自定义类而不是普通集合是个好主意吗?

java - 如何处理 ExpandableListView 子级的一行中不同 View 的单击事件

java - 从 H2 1.3.175 迁移到 1.4.195 的推荐方法是什么

c++ - 如何允许模板类构造函数根据基类型支持不同数量的参数?