[英]Java Abstract class Unusual behavior
抽象類:
public abstract class ParentClass {
private static ParentClass mpParentClass;
public ParentClass() {
mpParentClass = this;
}
public abstract void method1();
public static ParentClass getInstance() {
return mpParentClass;
}
}
兒童班:
public class ChildClass extends ParentClass{
@Override
public void method1() {
System.out.print("ChildClass class method");
}
}
測試類:
public class TestClass {
public static void main(String[] args) {
ChildClass cl = new ChildClass();
ParentClass.getInstance().method1();
}
}
在這里,我創建了一個抽象類和一個擴展父抽象類的Child類。
父抽象類包含對其自己的實例的引用,並通過靜態方法返回實例。
在Test類中,如果我不創建ChildClass的對象,則java拋出NullPointerException。
但是在創建了ChildClass的對象,然后查詢ParentClass的實例並調用抽象方法之后,它調用了ChildClass實現的方法。
我無法理解這種行為。 請有人解釋一下。
第一次實例化ChildClass時,使用parentClass的默認構造函數,該構造函數實例化具有ChildClass類型的私有字段。 如果不這樣做,私有字段mpParentClass不會實例化。 所以你有一個NullPointerException
ParentClass.getInstance()
是一個靜態方法,因此它不需要運行類的實例。
通過調用此方法,您將返回靜態成員mpParentClass
。 但默認情況下,此成員包含null
引用。
因此,如果不執行任何操作,這確實會導致NullPointerException
因為您沒有調用ParentClass
的構造函數。
在您的示例中,您首先創建ChildClass
的實例。
這將調用該類的默認構造函數。 這個默認構造函數具有調用超類的默認構造函數的標准行為(通過調用super()
)。
因此,通過實例化ChildClass
您可以調用ParentClass
的構造函數,該構造函數將mpParentClass
datamember設置為this。 這里指的是您正在創建的ChildClass
的實例。
因此在構造之后, mpParentClass
將包含新創建的ChildClass
實例。
這是正在發生的事情。
當您調用ChildClass
的構造函數時,隱含的是該方法中的第一個實際調用是超類構造函數。 如果你有一個超類構造函數需要/允許備用參數,你可以手動調用它。 但它正在發生在你身上。
調用超類構造函數時,會為該新實例分配static
引用,該實例是 ChildClass
實例。 (因為這就是this
,在這種情況下。)
如果你打電話:
new ChildClass();
new ParentClass() {
public void method1() {
System.out.println("Anonymous class!");
}
};
ParentClass.getInstance().method1();
你會看到"Anonymous class!"
,因為每次創建ParentClass
實現的任何實例時都會有一個靜態引用被重新分配。
關於NullPointerException
- 將mpParentClass
分配給值的唯一位置是ParentClass
的構造函數。 如果您從未創建ParentClass
的實例,則永遠不會調用此代碼,並且mpParentClass
將保留其原始值,即null
。 嘗試調用方法或訪問null
引用上的屬性是產生NullPointerException
。
要問的問題是:如果你從未實例化任何實現(通過'調用'它們的構造函數),你期望將mpParentClass
變量設置mpParentClass
,如果不是null
?
父類是抽象的,因此您不能直接使用構造函數。 默認情況下,靜態變量實例為null,這會導致您的NullPointerException。 設置此變量的唯一方法是調用構造函數,該構造函數僅在調用子類的構造函數時調用。
這是因為您只是在ParentClass
構造函數中指定靜態字段mpParentClass
。 因此,在創建ChildClass
實例之前, mpParentClass
為null。 在您的示例中,在創建派生類ChildClass
的實例時,將隱式調用基類ParentClass
構造函數。
我建議您使用單例模式嗎?
public class Singleton {
// Private constructor prevents instantiation from other classes
private Singleton() {}
/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
你正在創建一個ChildClass
然后通過不必要的ChildClass
調用它的method1()
。
您確實意識到this
將是ParentClass
構造函數中的ChildClass
實例,對吧? 它必須是,因為父類是抽象的,因此永遠不會有一個this
實例,將代表它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.