2

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 ?

kellogs
  • 2,837
  • 3
  • 38
  • 51

2 Answers2

5

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.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    For more examples of various problems resulting from calling overridden methods from a constructor, see Josh Bloch's _Effective Java_ – user949300 Dec 01 '11 at 08:24
  • >>virtual methods from constructors. Doh!... where have I heard that before ? in college maybe. Good reminder! Although Android made it less obvious I was doing just that. – kellogs Dec 01 '11 at 08:53
1

I tried the following using stub implementations of your objects in a Java VM.

public static void main(String[] args) {
    Context context = new Context();
    PublicDataSubservice pds = new PublicDataSubservice(context);
    XMPPService service = new XMPPService();
    pds.onServiceInstance(service);
}

No NullPointerException.

Am I missing something? I guess that onServiceInstance must actually get called as a result of context.getService(intent)?

ewan.chalmers
  • 16,145
  • 43
  • 60