构造函数中的自引用是否算作“转义”?

时间:2014-08-28 18:26:58

标签: java constructor

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

  

对最终字段的所有写入(以及可到达的变量)   间接地通过那些最终的领域)变得“冷冻”,#34; ...

     

如果在施工期间不允许物体的参考物逃逸,   一旦构造函数完成并且一个线程发布了一个   引用一个对象,保证该对象的最终字段   可见......

     

初始化安全性的一个警告是对象的问题   参考不得"逃避"它的构造函数 - 构造函数应该   不直接或间接地发布对象的引用   构造

我的问题是关于什么被认为是逃避。更具体地说,我想知道这个(有点人为和​​奇怪的)代码是否会产生一个安全可发布的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实际上是不可变的#34;因为不再可以访问允许可变性的父设置器。
  2. 对" this"的引用任何人都看不到构造函数(不是getter,也不是传递给任何其他对象)。那么,这算是"逃避"?
  3. 但整个对象被最终字段(自我)引用,因此理论上,它的整个内容应该被冻结"。 OTOH,最后一个字段本身是不可达的,所以也许它不算数;我完全可以想象JIT只是完全优化它。
  4. 如果" self"可以通过getter访问,但是getter不是在构造函数中调用的,它是否算作转义(假设它之前没有)?这样就可以防止JIT对它进行优化,这样它就必须“计算”,可能会这样吗?
  5. 所以,Child"是否可以安全地发布",如果不是,为什么,并且会自我get"改变答案?

    如果问题的目的不明确,我认为如果这样做,它将允许一个人轻松地制作一个可变的类"安全可发布",只需将其扩展为如上所示。

1 个答案:

答案 0 :(得分:4)

可能误解了逃避的意义。关键是this的值不能到达构造函数的任何外部代码。我想一些例子可以更好地解释它:

  • 将私有字段设置为this并不算作转义;
  • 调用私有方法,而不调用任何其他方法,并且不将this分配给异物的变量,不算作转义;
  • 调用属于this 的公开,可覆盖的方法计算为转义,除非该类为final。因此,当您致电this时,您的代码可以setAnswer转义,而不是在this转让给self时。为什么?因为子类可能会覆盖此方法并将this发布到任何外部代码。

有关selfself的推理的说明可以从this到达,这并不取决于外国来电者无法获得其价值的事实。方法可以在内部取消引用它就足够了。无论如何,关于冻结的规则没有考虑变量的访问级别。例如,一切都可以通过反射来获得。