Java 构造函数中的自引用是否算作“引用”;逃跑;?
在阅读JSR-133时,它说: 对最终字段(以及可访问的变量)的所有写入 间接地通过那些最后的字段)变成“冻结” 如果在构造期间不允许对象的引用转义, 然后,一旦构造函数完成,线程就会发布 引用对象时,该对象的最终字段保证 可见 初始化安全的一个警告是对象的 引用不能“转义”其构造函数——构造函数应该 不直接或间接发布对正在创建的对象的引用 建造的 我的问题是什么被认为是逃跑。更具体地说,我想知道这段(有些人为的和奇怪的)代码是否会产生一个安全可发布的子对象:Java 构造函数中的自引用是否算作“引用”;逃跑;?,java,constructor,Java,Constructor,在阅读JSR-133时,它说: 对最终字段(以及可访问的变量)的所有写入 间接地通过那些最后的字段)变成“冻结” 如果在构造期间不允许对象的引用转义, 然后,一旦构造函数完成,线程就会发布 引用对象时,该对象的最终字段保证 可见 初始化安全的一个警告是对象的 引用不能“转义”其构造函数——构造函数应该 不直接或间接发布对正在创建的对象的引用 建造的 我的问题是什么被认为是逃跑。更具体地说,我想知道这段(有些人为的和奇怪的)代码是否会产生一个安全可发布的子对象: class Parent {
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();
}
}
this
的值不能到达构造函数所不熟悉的任何代码。我认为有几个例子可以更好地解释这一点:
- 将私有字段设置为
不算作转义李>此
- 调用私有方法,而私有方法不会调用任何其他方法,也不会将
赋值给外部对象的变量,这不算作转义李>此
- 除非类是
,否则调用属于final
的公共可重写方法将被视为转义。因此,当您调用此
时,您的代码允许setAnswer
转义,而不是将this
分配给this
时。为什么?因为子类可能会重写此方法并将self
发布到任何外部代码此
有关
self
的推理说明:self
可从此
访问,这并不取决于外部调用方无法获取其值这一事实。一个方法可以在内部解除对它的引用就足够了。无论如何,关于冻结的规则没有考虑变量的访问级别。例如,一切都可以通过反射来访问。阅读相关段落:如果在将引用存储到final
字段之前,没有另一个线程可以通过看似合理的执行序列看到它,那么引用是否会被视为“转义”呢?我不记得JLS是如何定义它的,但这就是规则的意义,是的。你在我的例子中发现了一个缺陷;调用Parent.setAnswer()。虽然我一般都知道在构造函数中调用可重写的方法是一个大难题,但在这种情况下我并没有想到这一点(我也不会把它算作“逃避这个”!)。窗台,你的回答让我缺少;若我并没有调用setAnswer(),比如说,若答案是受保护的,而我是直接设置的,那个么这个孩子可以安全地发布吗?如果没有“self”,它就不会,但我仍然不确定这里的“self”是否有帮助。好吧,它显然是根据您在self
中注意到的定义得出的,您是安全的。最终的结果确实让人觉得有点不对劲——为什么我们需要如此愚蠢的技术来实现这一点呢?考虑到一个我们希望“在构建后不改变”并安全发布的预先存在的、可变的类型,这可能会允许它。当然,OTOH更清晰、更明显的解决方案是创建一个简单的“Holder”,并最终引用可变对象,然后返回Holder。基本上,这只节省了一小部分分配,但大多数情况下,我只是好奇。