[java] 抽像類是否可以有構造函數?


Answers

如果您處於以下某種情況,您可以在抽像類中定義構造函數:

  • 您希望在實際發生子類的實例化之前執行一些初始化(對抽像類的字段)
  • 你已經在抽像類中定義了最終字段,但是你沒有在聲明中初始化它們; 在這種情況下,你必須有一個構造函數來初始化這些字段

注意:

  • 你可以定義多個構造函數(使用不同的參數)
  • 你可以(應該)定義你所有的構造函數都是受保護的(無論如何,它們都是公開的)
  • 你的子類構造函數可以調用抽像類的一個構造函數; 它甚至可能需要調用它(如果抽像類中沒有無參數構造函數)

無論如何,不要忘記,如果你沒有定義構造函數,那麼編譯器會自動為你生成一個(這個是公共的,沒有參數,什麼都不做)。

Question

抽像類是否可以有構造函數?

如果是這樣,它如何被使用和用於什麼目的?




是的,你可以添加一個,正如已經提到的初始化Abstract類變量。 但是如果你不明確地聲明一個,它反正有一個隱含的構造函數“Constructor Chaining”來工作。




考慮這個:

abstract class Product { 
    int value;
    public Product( int val ) {
        value= val;
    }
    abstract public int multiply();
}

class TimesTwo extends Product {
    public int mutiply() {
       return value * 2;
    }
}

超類是抽象的,並有一個構造函數。




是的抽像類可以有一個構造函數。您可以在抽像類中重載任意數量的構造函數。這些構造函數可用於初始化擴展抽像類的對象的初始狀態。 正如我們所知道的,我們不能創建抽像類的對象,因為對像是由“新”關鍵字創建的,而不是由構造函數創建的......它們僅用於初始化子類Objects的狀態。




抽像類可以有一個構造函數,儘管它不能被實例化。 但是抽像類中定義的構造函數可以用於此抽像類的具體類的實例化。 檢查JLS

如果嘗試使用類實例創建表達式創建抽像類的實例,則會出現編譯時錯誤

抽像類的一個非自身抽像類的子類可能會被實例化,從而導致抽像類的構造函數的執行,並因此執行該類的實例變量的字段初始值設定項。




是的抽像類可以有構造函數

是的,當我們將類定義為抽像類時,它不能實例化,但這並不意味著Abstract類不能有構造函數。 每個抽像類必須有一個具體的子類,它將實現該抽像類的抽象方法。

當我們創建任何子類的對象時,相應的繼承樹中的所有構造函數都是從上到下的方法調用的。 同樣的情況適用於抽像類。 雖然我們不能創建抽像類的對象,但是當我們創建抽像類的具體和子類的類的對象時,抽像類的構造函數會自動調用。因此,我們可以在抽像類中創建構造函數。

注意:非抽像類不能有抽象方法,但抽像類可以有非抽象方法。 原因與構造函數類似,區別在於不會自動調用,我們可以調用super()。 也沒有什麼像抽象構造函數,因為它根本沒有意義。




在具體類中,具體類型Fnord的構造函數的聲明有效地暴露了兩件事:

  • 代碼可以請求創建Fnord實例的方式

  • 正在構建的Fnord派生的類型的實例可以請求初始化所有基類功能的方法。

雖然也許應該有一種方法可以分別控制這兩種能力,但對於每種具體的類型,一種定義將使兩種能力都成為可能。 儘管第一種能力對抽像類沒有意義,但第二種能力對於抽像類而言與其他任何抽像類一樣有意義,因此它的聲明同樣必要且有用。




由於抽像類可以具有所有訪問修飾符的變量,因此必須將它們初始化為默認值,因此構造函數是必需的。 當你實例化子類時,抽像類的構造函數被調用並且變量被初始化。

相反,一個接口只包含常量變量意味著它們已經被初始化。 所以接口不需要構造函數。




是的,抽像類構造函數通常用於超級調用所有子類通用的初始化事件




正如javafuns here所描述的,這是一個例子:

public abstract class TestEngine
{
   private String engineId;
   private String engineName;

   public TestEngine(String engineId , String engineName)
   {
     this.engineId = engineId;
     this.engineName = engineName;
   }
   //public gettors and settors
   public abstract void scheduleTest();
}


public class JavaTestEngine extends TestEngine
{

   private String typeName;

   public JavaTestEngine(String engineId , String engineName , String typeName)
   {
      super(engineId , engineName);
      this.typeName = typeName;
   }

   public void scheduleTest()
   {
     //do Stuff
   }
}



Links