获取这个基类:
public abstract class XMPPSubservice
{
protected XMPPService mTheService;
protected XMPPSubservice(Context context)
{
Intent intent = new Intent(context, XMPPService.class);
context.startService(intent);
}
public void onServiceInstance(XMPPService service) {
// TODO Auto-generated method stub
mTheService = service;
}
}
这个派生类:
public class PublicDataSubservice extends XMPPSubservice
{
private final SomeObject mObj = new SomeObject();
public PublicDataSubservice(Context context) {
super(context);
}
@Override
public void onServiceInstance(XMPPService service)
{
super.onServiceInstance(service);
mObj.doSomethingWith(mTheService);
}
}
目标是只调用 mObj.doSomethingWith(mTheService);在 mTheService 生效后(发生在基类中)。问题是它总是在 mObj 行吐出 NPE。我能理解为什么会这样,但对我来说这看起来很奇怪。那么这是 DVM 的错误还是功能? JVM 怎么样?
最佳答案
这是完全正确的,并且也会出现在“vanilla”Java 中。
实例变量初始值设定项仅在父类(super class)构造函数完成执行后在构造函数体的开始处执行。因此,当 XMPPSubservice
构造函数正在执行时,mObj
为 null - 然后您从构造函数调用虚拟方法,并执行 PublicDataService
中的覆盖。
道德:不要从构造函数中调用虚拟方法,除非你真的必须这样做,在这种情况下你应该非常仔细地记录它们。 (偶尔它很有用,但你应该努力避免它。)基本上这意味着你最终会调用一个可能部分初始化的对象,这就是这里发生的事情。
关于java虚拟方法: feature or bug?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8338145/