簡體   English   中英

Java抽象類異常行為

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM