문제

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 ?

도움이 되었습니까?

해결책

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.

다른 팁

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)?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top