java虚方法:功能还是bug?

kel*_*ogs 2 java jvm-languages dalvik

拿这个基类:

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

而这个派生类:

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);
    }

}
Run Code Online (Sandbox Code Playgroud)

目标是只调用mObj.doSomethingWith(mTheService); mTheService生效后(发生在基类中).事情是它总是在mObj线上吐出NPE.我能理解为什么会这样,但它对我来说看起来很不可思议.那么这是DVM的一个bug还是一个功能?JVM怎么样?

Jon*_*eet 5

这是完全正确的,也会发生在"vanilla"Java中.

实例变量初始值设定项仅在超类构造函数完成执行在构造函数体的开头执行.因此,当XMPPSubservice构造函数执行时,mObj为null - 然后从构造函数中调用虚方法,并PublicDataService执行覆盖.

道德:不要从构造函数中调用虚方法,除非你真的必须这样做,在这种情况下你应该仔细记录它们.(偶尔它很有用,但你应该尽力避免它.)基本上它意味着你最终会调用一个可能部分初始化的对象,这就是这里发生的事情.