Java 构造函数中的对象逃逸总是一个问题吗?
出于线程安全的原因,有争议:
不要让 this 引用在构造过程中逃逸。
但这始终是一个问题,应该通过使用 newInstance() 方法来避免吗?在我的模型类中,我有一个 TableModel ,它应该在模型类中实例化,但它也需要对模型类的引用:
public class MainModel {
TableModel tableMode;
public MainModel() {
tableModel = new MyTableModel(this);
}
}
如果构造函数不立即使用它,那么它是安全的还是应该以任何方式避免它?
For thread-safety reasons it is argumented:
Do not allow the this reference to escape during construction.
But is this always an issue and should be avoided by using newInstance()
methods? Inside my model class I have a TableModel which should be instantiated, within the model class, but which also requires a reference to the model class:
public class MainModel {
TableModel tableMode;
public MainModel() {
tableModel = new MyTableModel(this);
}
}
If the constructor does not use this right away is it then safe or should it be avoided in any means?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果 MyTableModel 中的任何内容都不会在其他线程等中执行任何操作 - 或者将变量复制到其他共享数据(例如静态变量) - 那么它是安全的。
当然,如果 MyTableModel 开始在其构造函数内调用 MainModel 引用上的方法,那么它将在尚未完全初始化的对象上调用它们,这可以导致问题 - 但这与线程无关。
我写了更多博客不久前就谈到过这一点。
If nothing in the
MyTableModel
is going to do anything in other threads etc - or copy the variable to some other shared data, such as a static variable - then it's safe.Of course, if
MyTableModel
starts calling methods on theMainModel
reference within its constructor, then it'll be calling them on a not-completely-initialized-yet object, which can cause issues - but that's not really threading related.I blogged a bit more on this a while ago.
不,我不认为这总是一个问题。在我看来,一个好的类的设计使得构造函数限制它对其依赖项所做的活动,将其行为仅限于初始化。如果是这种情况,那么
this
仅仅因为将其泄漏给另一个构造函数就泄漏到另一个线程,那将是非常令人惊讶的。唯一一次根本不允许您泄漏对
this
的引用是在调用超级构造函数之前。换句话说,您无法将参数传递给依赖于this
的超级构造函数,无论是由于您调用实例方法还是使用this
构造某些内容。我认为更好的问题可能是为什么
MyTableModel
需要查看MainModel
的实例?通常,双向可见性是某些有害耦合的标志。No, I don't think it's always a problem. In my opinion a good class is designed such that the constructor limits the activity it does on its dependents, limiting its behaviour only to initialization. If that's the case it would be very surprising for
this
to leak to another thread simply because you leaked it to another constructor.The only time you are not permitted at all to leak a reference to
this
is before the super contructor has been called. In other words, you can't pass an argument to the super constructor that has a dependency onthis
, be it due to you calling an instance method or constructing something usingthis
.I think a better question might be why does
MyTableModel
need to see an instance ofMainModel
? Often bi-directional visibility is a sign of some harmful coupling.最佳实践不是纠正错误,而是最不可能引入错误、令人困惑或难以维护的模式。我见过一些非常困难的代码,但运行得很好。
例如,我记得一个名为
c
的类,它完全写在一行中以节省空间(没有换行符),并且仅使用单字符变量/字段,并且具有一到两个字符方法。这并不是故意混淆的,开发者认为这是最有效的。只要你不需要理解它或改变它,这个类就可以很好地工作。Best pratice is not about correcting bugs, but patterns which are least likely to introduce bugs, be confusing or difficult to maintain. I have seen some increadibly difficult code which works just fine.
e.g. I remember one class called
c
which was written entirely on one line to save space (no line breaks) and only used single character variables/fields and had one to two character methods. This wasn't deliberately obfuscated, the developer thought this was the most efficient. The class worked fine as long as you didn't need to understand it of change it.