asa*_*n74 79 java constructor netbeans this netbeans-6.9
我想避免(大多数)Netbeans 6.9.1的警告,我的'Leaking this in constructor'警告有问题.
我理解这个问题,在构造函数中调用一个方法并传递" this"是危险的,因为" this"可能没有完全初始化.
很容易在我的单例类中修复警告,因为构造函数是私有的,只能从同一个类中调用.
旧代码(简化):
private Singleton() {
...
addWindowFocusListener(this);
}
public static Singleton getInstance() {
...
instance = new Singleton();
...
}
Run Code Online (Sandbox Code Playgroud)
新代码(简化):
private Singleton() {
...
}
public static Singleton getInstance() {
...
instance = new Singleton();
addWindowFocusListener( instance );
...
}
Run Code Online (Sandbox Code Playgroud)
如果构造函数是公共的并且可以从其他类调用,则此修复不起作用.如何修复以下代码:
public class MyClass {
...
List<MyClass> instances = new ArrayList<MyClass>();
...
public MyClass() {
...
instances.add(this);
}
}
Run Code Online (Sandbox Code Playgroud)
当然我想要一个修复,它不需要使用这个类修改我的所有代码(例如通过调用init方法).
chi*_*oro 44
既然你确保把你instances.add(this)放在构造函数的末尾,你应该安全告诉编译器简单地抑制警告 (*).就其本质而言,警告并不一定意味着出现了问题,只需要您的注意.
如果您知道自己在做什么,可以使用@SuppressWarnings注释.就像Terrel在他的评论中提到的那样,以下注释是从NetBeans 6.9.1开始的:
@SuppressWarnings("LeakingThisInConstructor")
Run Code Online (Sandbox Code Playgroud)
(*)更新:正如Isthar和Sergey所指出的,有些情况下"泄漏"的构造函数代码看起来非常安全(如在您的问题中),但事实并非如此.有更多读者可以批准吗?我正考虑因上述原因删除这个答案.
Ish*_*tar 36
[chiccodoro备注:解释为什么/何时泄漏this可能导致问题,即使泄漏语句最后放在构造函数中:]
最终字段语义不同于"普通"字段语义.一个例子,
我们玩网络游戏.让我们让一个Game对象从网络中检索数据,并让Player对象监听游戏中的事件,从而采取相应的行动.游戏对象隐藏所有网络细节,玩家只对事件感兴趣:
import java.util.*;
import java.util.concurrent.Executors;
public class FinalSemantics {
public interface Listener {
public void someEvent();
}
public static class Player implements Listener {
final String name;
public Player(Game game) {
name = "Player "+System.currentTimeMillis();
game.addListener(this);//Warning leaking 'this'!
}
@Override
public void someEvent() {
System.out.println(name+" sees event!");
}
}
public static class Game {
private List<Listener> listeners;
public Game() {
listeners = new ArrayList<Listener>();
}
public void start() {
Executors.newFixedThreadPool(1).execute(new Runnable(){
@Override
public void run() {
for(;;) {
try {
//Listen to game server over network
Thread.sleep(1000); //<- think blocking read
synchronized (Game.this) {
for (Listener l : listeners) {
l.someEvent();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
public synchronized void addListener(Listener l) {
listeners.add(l);
}
}
public static void main(String[] args) throws InterruptedException {
Game game = new Game();
game.start();
Thread.sleep(1000);
//Someone joins the game
new Player(game);
}
}
//Code runs, won't terminate and will probably never show the flaw.
Run Code Online (Sandbox Code Playgroud)
似乎一切都很好:对列表的访问是正确同步的.缺点是这个例子将Player.this泄漏给正在运行线程的Game.
决赛是非常可怕的:
...编译器有很大的自由来跨同步障碍移动最终字段的读取...
这几乎打败了所有正确的同步.但幸运的是
在该对象完全初始化之后只能看到对象引用的线程可以保证看到该对象
final字段的正确初始化值.
在该示例中,构造函数将对象引用写入列表.(因此尚未完全初始化,因为构造函数没有完成.)在写入之后,构造函数仍未完成.它只需要从构造函数返回,但我们假设它还没有.现在,执行程序可以完成其工作并向所有侦听器广播事件,包括尚未初始化的播放器对象!播放器(名称)的最后一个字段可能无法写入,并将导致打印null sees event!.
Col*_*ert 13
您拥有的最佳选择:
WindowFocusListener在另一个课程中提取你的部分(也可以是内部或匿名).最好的解决方案,这样每个类都有特定的目的.使用单例作为漏洞构造函数的变通方法并不是很有效.
Nat*_* W. 12
这是创建类的实例的工厂有用的好例子.如果Factory负责创建类的实例,那么您将拥有一个调用构造函数的集中位置,并且init()向代码中添加必需的方法将是微不足道的.
关于你的直接解决方案,我建议你移动任何泄漏this到构造函数最后一行的调用,然后在你"证明"这样做是安全的时候用注释来抑制它们.
在IntelliJ IDEA中,您可以使用行上方的以下注释来禁止此警告:
//noinspection ThisEscapedInObjectConstruction
| 归档时间: |
|
| 查看次数: |
49357 次 |
| 最近记录: |