Search code examples
javadalvikjvm-languages

java virtual methods: feature or bug?


Take this base class:

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

}

And this derived class:

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

}

The goal was to only call mObj.doSomethingWith(mTheService); after the mTheService became valid (which happened in the base class). Thing was it always spat out NPE at the mObj line. I can understand why that happened, but it looks wonky to me. So is this a bug or a feature of DVM ? How about JVM ?


Solution

  • That's entirely correct, and would occur in "vanilla" Java too.

    Instance variable initializers are only executed at the start of the constructor body after the superclass constructor has completed executing. So while the XMPPSubservice constructor is executing, mObj is null - you then call a virtual method from the constructor, and the override in PublicDataService executes.

    Moral: don't call virtual methods from constructors, unless you really have to, in which case you should document them really carefully. (Very occasionally it's useful, but you should try hard to avoid it.) Basically it means you end up with a call on a potentially-partially-initialized object, which is what's happening here.