виртуальные методы Java: функция или ошибка? - PullRequest
2 голосов
/ 01 декабря 2011

Возьми этот базовый класс:

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 вступил в силу (что произошло в базовом классе). Дело в том, что он всегда выплевывал NPE на линии mObj. Я могу понять, почему это произошло, но для меня это выглядит странно. Так это ошибка или особенность DVM? Как насчет JVM?

Ответы [ 2 ]

5 голосов
/ 01 декабря 2011

Это совершенно правильно и может произойти и в "ванильной" Java.

Инициализаторы переменных экземпляра выполняются только в начале тела конструктора после , когда конструктор суперкласса завершил выполнение.Таким образом, пока выполняется конструктор XMPPSubservice, mObj равен нулю - затем вызывается виртуальный метод из конструктора, и выполняется переопределение в PublicDataService.

Мораль: не вызывать виртуальные методы изконструкторы, если вы действительно не должны, и в этом случае вы должны действительно тщательно их документировать.(Очень редко это полезно, но вы должны изо всех сил избегать этого.) В основном это означает, что вы в конечном итоге вызываете потенциально частично инициализированный объект, что и происходит здесь.

1 голос
/ 01 декабря 2011

Я попробовал следующее с использованием реализаций заглушек ваших объектов в виртуальной машине Java.

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

Нет NullPointerException.

Я что-то упустил? Я думаю, что onServiceInstance должен быть вызван в результате context.getService(intent)?

...