2011-12-01 41 views
2

以這個基類:java虛擬方法:功能還是bug?

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成爲有效後(發生在基類中)之後。事情總是在mObj線爆出NPE。我可以理解爲什麼會發生這種事,但對我來說看起來很不自信。那麼這是DVM的缺陷還是功能? JVM如何?

回答

5

這是完全正確的,並且會發生在「vanilla」Java中。

實例變量初始值設定項僅在構造函數主體開始時在超類構造函數完成執行後的後執行。因此,在執行XMPPSubservice構造函數時,mObj爲空 - 然後您從構造函數調用虛方法,並執行PublicDataService中的覆蓋。

道德:不要從構造函數調用虛擬方法,除非你真的需要,在這種情況下,你應該仔細記錄它們。 (有時候它很有用,但你應該儘量避免它。)基本上,它意味着你最終會調用一個可能部分初始化的對象,這就是發生在這裏的事情。

+1

有關調用來自構造函數的重寫方法導致的各種問題的更多示例,請參閱構造函數中的Josh Bloch的_Effective Java_ – user949300

+0

>>虛方法。啊!......我以前在哪裏聽過?也許在大學裏。好的提醒!雖然Android讓它變得不那麼明顯,但我正是這麼做的。 – kellogs

1

我在Java VM中使用對象的存根實現嘗試了以下方法。

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)而被調用?

+0

是的。忘了提到這一點 – kellogs