Java 构造函数中的自引用是否算作“引用”;逃跑;?

Java 构造函数中的自引用是否算作“引用”;逃跑;?,java,constructor,Java,Constructor,在阅读JSR-133时,它说: 对最终字段(以及可访问的变量)的所有写入 间接地通过那些最后的字段)变成“冻结” 如果在构造期间不允许对象的引用转义, 然后,一旦构造函数完成,线程就会发布 引用对象时,该对象的最终字段保证 可见 初始化安全的一个警告是对象的 引用不能“转义”其构造函数——构造函数应该 不直接或间接发布对正在创建的对象的引用 建造的 我的问题是什么被认为是逃跑。更具体地说,我想知道这段(有些人为的和奇怪的)代码是否会产生一个安全可发布的子对象: class Parent {

在阅读JSR-133时,它说:

对最终字段(以及可访问的变量)的所有写入 间接地通过那些最后的字段)变成“冻结”

如果在构造期间不允许对象的引用转义, 然后,一旦构造函数完成,线程就会发布 引用对象时,该对象的最终字段保证 可见

初始化安全的一个警告是对象的 引用不能“转义”其构造函数——构造函数应该 不直接或间接发布对正在创建的对象的引用 建造的

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

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();
    }
}
  • 首先,虽然父项显然是可变的,但子项“实际上是不可变的”,因为将允许可变的父项setter不再是可访问的
  • 构造函数中对“this”的引用对任何人都不可见(不是getter,也不是传递给任何其他对象)。那么,这算是“逃跑”吗
  • 但对象作为一个整体被最后一个字段(self)引用,因此在理论上,它的全部内容应该被“冻结”。OTOH,最后一个字段本身是不可到达的,所以可能不算数;我可以很好地想象JIT完全优化了它
  • 如果“self”是通过getter访问的,但是getter没有在构造函数中调用,那么它是否算作转义(假设之前没有)?这将阻止JIT优化它,所以它必须“计数”,也许
  • 那个么,孩子“可以安全地发表”吗?若不能,为什么?一个“自我”的获得者会改变答案吗

    如果这个问题的目的不清楚,我认为如果这个方法有效,那么只需如上所示扩展它,就可以轻松地使可变类“安全发布”。

    您可能误解了转义的含义。关键是
    this
    的值不能到达构造函数所不熟悉的任何代码。我认为有几个例子可以更好地解释这一点:

    • 将私有字段设置为
      不算作转义
    • 调用私有方法,而私有方法不会调用任何其他方法,也不会将
      赋值给外部对象的变量,这不算作转义
    • 除非类是
      final
      ,否则调用属于
      的公共可重写方法将被视为转义。因此,当您调用
      setAnswer
      时,您的代码允许
      this
      转义,而不是将
      this
      分配给
      self
      时。为什么?因为子类可能会重写此方法并将
      发布到任何外部代码

    有关
    self
    的推理说明:
    self
    可从
    访问,这并不取决于外部调用方无法获取其值这一事实。一个方法可以在内部解除对它的引用就足够了。无论如何,关于冻结的规则没有考虑变量的访问级别。例如,一切都可以通过反射来访问。

    阅读相关段落:如果在将引用存储到
    final
    字段之前,没有另一个线程可以通过看似合理的执行序列看到它,那么引用是否会被视为“转义”呢?我不记得JLS是如何定义它的,但这就是规则的意义,是的。你在我的例子中发现了一个缺陷;调用Parent.setAnswer()。虽然我一般都知道在构造函数中调用可重写的方法是一个大难题,但在这种情况下我并没有想到这一点(我也不会把它算作“逃避这个”!)。窗台,你的回答让我缺少;若我并没有调用setAnswer(),比如说,若答案是受保护的,而我是直接设置的,那个么这个孩子可以安全地发布吗?如果没有“self”,它就不会,但我仍然不确定这里的“self”是否有帮助。好吧,它显然是根据您在
    self
    中注意到的定义得出的,您是安全的。最终的结果确实让人觉得有点不对劲——为什么我们需要如此愚蠢的技术来实现这一点呢?考虑到一个我们希望“在构建后不改变”并安全发布的预先存在的、可变的类型,这可能会允许它。当然,OTOH更清晰、更明显的解决方案是创建一个简单的“Holder”,并最终引用可变对象,然后返回Holder。基本上,这只节省了一小部分分配,但大多数情况下,我只是好奇。