簡體   English   中英

如果父類具有帶參數的構造函數,為什么需要在父類中使用默認構造函數?

[英]Why default constructor is required in a parent class if it has an argument-ed constructor?

如果父類具有帶參數的構造函數,為什么在父類中需要(顯式)默認構造函數

class A {    
  A(int i){    
  }
}

class B extends A {
}

class Main {    
  public static void main(String a[]){
    B b_obj = new B();
  }
}

這將是一個錯誤。

這里有兩個方面在起作用:

  • 如果您確實明確指定了構造函數(如在A ),則 Java 編譯器不會為您創建無參數構造函數。

  • 如果您沒有顯式指定構造函數(如在B ),Java 編譯器將為您創建一個無參數構造函數,如下所示:

     B() { super(); }

(可訪問性取決於類本身的可訪問性。)

那是試圖調用超類無參數構造函數 - 所以它必須存在。 您有三個選擇:

  • A顯式提供無參數構造函數
  • B中顯式提供無參數構造函數,該構造函數使用適當的int參數顯式調用基類構造函數。
  • B提供一個參數化構造函數,它調用基類構造函數

如果父類具有帶參數的構造函數,為什么在父類中需要(顯式)默認構造函數

我會說這種說法並不總是正確的。 理想情況下它不是必需的

規則是:如果您顯式提供了帶參數的構造函數,則該類無法使用默認構造函數(無參數)。

For Example :   
class A {    
  A(int i){    
  }
}

class B extends A {
}

所以當你寫

B obj_b = new B();

它實際上調用了java提供的隱式構造函數給B,B又調用了super(),理想情況下應該是A()。 但是由於您為 A 提供了帶參數的構造函數,因此默認構造函數 i:e A() 對 B() 不可用。

這就是您需要為 B() 專門聲明 A() 以調用 super() 的原因。

如果子類構造函數沒有顯式調用超類的其他構造函數,則每個子類構造函數都會調用超類的默認構造函數。 因此,如果您的子類構造函數顯式調用您提供的超類構造函數(帶參數),則超類中不需要無參數構造函數。 因此,將編譯以下內容:

class B extends A{
     B(int m){
        super(m);
     }
}

但是以下不會編譯,除非您在超類中明確提供沒有 args 構造函數:

class B extends A{
     int i; 
     B(int m){
        i=m;
     }
}

假設您打算編寫class B extends A

每個構造函數都必須調用超類構造函數; 如果不是,則隱式調用無參數超類構造函數。

如果(且僅當)一個類沒有聲明構造函數,Java 編譯器會給它一個默認構造函數,它不帶參數並調用超類的無參數構造函數。 在您的示例中, A聲明了一個構造函數,因此沒有這樣的默認構造函數。 B沒有聲明構造函數,但無法獲得默認構造函數,因為它的超類沒有可調用的無參數構造函數。 由於類必須始終具有構造函數,因此這是編譯器錯誤。

Why default constructor is required(explicitly) in a parent class if it 
has an argumented constructor

不必要!

現在在你的 B 班

class B extends A {
}

您尚未在 B 類中提供任何構造函數,因此將放置默認構造函數。 現在的規則是每個構造函數都必須調用它的超類構造函數之一。 在您的情況下,B 類中的默認構造函數將嘗試調用 A 類(它的父類)中的默認構造函數,但由於您在 A 類中沒有默認構造函數(因為您在 A 類中明確提供了一個帶參數的構造函數,因此您將在 A 類中沒有默認構造函數)你會得到一個錯誤。

你可能會做的是

在 A 類中不提供 args 構造函數。

A()
{
  //no arg default constructor in Class A
}

要么

明確地在 B 中寫入 no args 構造函數,並使用一些默認的 int 參數調用您的 super。

B()
{
    super(defaultIntValue);
}

底線是,要創建一個對象,必須調用繼承層次結構中每個父級的完全構造函數。 調用哪個實際上是您的設計選擇。 但是,如果您沒有明確提供任何 java 會將默認構造函數 super() 調用作為每個子類構造函數的第一行,現在如果您在超類中沒有它,那么您將收到錯誤。

使用構造函數時需要注意一些事項,以及如何在基類和超類中聲明它們。 這可能會變得有些混亂,因為超類或基類中構造函數的可用性或存在性可能有很多。 我將嘗試深入研究所有可能性:

  • 如果您在任何類(基類/超類)中顯式定義構造函數,Java 編譯器將不會在相應的類中為您創建任何其他構造函數。

  • 如果您沒有在任何類(基類/超類)中顯式定義構造函數,Java 編譯器將在相應的類中為您創建一個無參數的構造函數。

  • 如果您的類是從超類繼承的基類,並且您沒有在該基類中顯式定義構造函數,則編譯器不僅會為您創建無參數構造函數(如上點),而且還會從超類隱式調用無參數構造函數。

     class A { A() { super(); } }
  • 現在,如果您沒有明確鍵入 super()、(或 super(parameters)),編譯器會在您的代碼中為您放入 super()。
  • 如果 super() 被調用(由編譯器顯式或隱式調用),編譯器將期望您的超類具有不帶參數的構造函數。 如果它在你的超類中沒有找到任何沒有參數的構造函數,它會給你一個編譯器錯誤。

  • 類似地,如果調用 super(parameters) ,編譯器將期望您的超類具有帶參數的構造函數(參數的數量和類型應匹配)。 如果它在你的超類中找不到這樣的構造函數,它會給你一個編譯器錯誤。 ( Super(parameters) 永遠不能被編譯器隱式調用。如果需要,它必須顯式地放入你的代碼中。)

我們可以從上面的規則中總結出一些東西

  • 如果您的超類只有一個帶參數的構造函數而沒有無參數的構造函數,則您的構造函數中必須有一個顯式的 super(parameters) 語句。 這是因為如果您不這樣做, super() 語句將隱式放入您的代碼中,並且由於您的超類沒有無參數構造函數,它將顯示編譯器錯誤。
  • 如果你的超類有一個帶參數的構造函數和另一個無參數的構造函數,那么你的構造函數中就沒有必要有一個顯式的 super(parameters) 語句。 這是因為編譯器會隱式地將 super() 語句放入您的代碼中,並且由於您的超類具有無參數構造函數,因此它可以正常工作。
  • 如果你的超類只有一個無參數的構造函數,你可以參考上面的觀點,因為它是一樣的。

另一件要注意的事情是,如果您的超類有一個私有構造函數,那么在您編譯子類時會產生錯誤。 這是因為如果您不在子類中編寫構造函數,它將調用超類構造函數,而隱式 super() 將嘗試在超類中查找無參數構造函數但找不到。

說這個編譯,你希望它打印什么?

class A{
  A(int i){
    System.out.println("A.i= "+i);
  }
}

class B extends A {
  public static void main(String... args) {
    new B();
  }
}

當 A 被構造為i ,必須傳遞一個值,但是編譯器不知道它應該是什么,因此您必須在構造函數中明確指定它(任何構造函數,它都不必是默認的)

當我們有參數構造函數時。 我們通過設計明確綁定到消費者。 他不能在沒有參數的情況下創建該類的對象。 有時我們需要強制用戶提供價值。 對象只能通過提供參數(默認值)來創建。

class Asset
{
    private int id;
    public Asset(int id)
    {
        this.id = id;
    }
}

class Program
{
    static void Main(string[] args)
    {
        /* Gives Error - User can not create object. 
         * Design bound
         */
        Asset asset1 = new Asset();/* Error */
    }
}

連子類都不能創建。 因此,這是良好設計的行為。

擴展類時,會自動添加默認的超類構造函數。

public class SuperClass {
}

public class SubClass extends SuperClass {
   public SubClass(String s, Product... someProducts) {
      //super(); <-- Java automatically adds the default super constructor
   }
}

但是,如果您重載了超類構造函數,這將取代默認值,因此調用super()將導致編譯錯誤,因為它不再可用。 然后,您必須顯式添加重載的構造函數或創建一個無參數的構造函數。 請參閱以下示例:

public class SuperClass {
   public SuperClass(String s, int x) {
     // some code
   }
}

public class SubClass extends SuperClass {
   public SubClass(String s, Product... someProducts) {
      super("some string", 1);
   }
}

要么...

public class SuperClass {
   public SuperClass() {
     // can be left empty.
   }
}

public class SubClass extends SuperClass {
   public SubClass(String s, Product... someProducts) {
      //super(); <-- Java automatically adds the no-parameter super constructor
   }
}

因為如果您想阻止創建沒有任何數據的對象,這是一種好方法。

當然,如果這樣寫它是一個錯誤,它不是JAVA。

如果您將使用 JAVA 語法,則不會出錯。

如果在單獨的文件/包中,A 類和 B 類對彼此一無所知。

A 類根本不需要默認構造函數,它只使用參數構造函數就可以正常工作。

如果 B 擴展了 A,您只需在 B 的構造函數中調用 super(int a) ,一切都很好。 對於不調用擴展超類的 super(空/或不)的構造函數,編譯器將添加對 super() 的調用。

如需進一步閱讀,請參閱使用關鍵字超級

我猜這是因為當您有一個空參數列表時,無法實例化超級變量。 對於空參數列表,我的意思是如果超類具有非參數構造函數,編譯器可以添加隱式 super() 。

例如,如果您鍵入:

int a;
System.out.print(a);

你會得到一個錯誤,我認為是相同的邏輯錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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