2009-12-07 148 views
0

有人能指出我誤解的是什麼嗎?Java:抽象類構造函數和this()

我有兩個班,一個抽象的,具體如下:

public abstract class Abstract 
{ 
    protected static int ORDER = 1; 

    public static void main (String[] args) 
    { 
     Concrete c = new Concrete("Hello"); 
    } 

    public Abstract() 
    { 
     Class c = this.getClass(); 
     System.out.println(ORDER++ + ": Class = " 
      + c.getSimpleName() 
      + "; Abstract's no-arg constructor called."); 
    } 

    public Abstract(String arg) 
    { 
     this(); 
     Class c = this.getClass(); 
     System.out.println(ORDER++ + ": Class = " 
      + c.getSimpleName() 
      + "; Abstract's 1-arg constructor called."); 
    } 
} 

public class Concrete extends Abstract 
{ 
    public Concrete() 
    { 
     super(); 
     Class c = this.getClass(); 
     System.out.println(ORDER++ + ": Class = " 
      + c.getSimpleName() 
      + "; Concrete's no-arg constructor called."); 
    } 

    public Concrete(String arg) 
    { 
     super(arg); 
     Class c = this.getClass(); 
     System.out.println(ORDER++ + ": Class = " 
      + c.getSimpleName() 
      + "; Concrete's 1-arg constructor called."); 
    } 
} 

當我運行此我得到以下輸出:

1)Class =混凝土;摘要的no-arg 構造函數調用。
2)Class = 混凝土;調用Abstract的1-arg構造函數 。
3)Class = Concrete; 混凝土的1-arg構造函數調用。

我的問題是這樣的:爲什麼不從Abstract的字符串arg構造函數調用this()在Concrete上調用這個無參數構造函數?或者,也許更有針對性的是,有沒有辦法讓Abstract的String arg構造函數在Concrete上調用no-arg構造函數,從而允許構造函數的「適當」鏈接?

回答

7

否 - 構造函數鏈總是要麼側向(在同一類型)或向上(到父類型)。

不要忘記呼叫已在編譯時得到解決 - 和Abstract不知道其它類會從它,或者他們將有什麼構造函數來推導。

可以調用Abstract構造內的虛擬方法,並在Concrete重寫方法......但我會勸你做到這一點。特別是,Concrete的構造函數體將不會被執行,變量初始值設定項也不會被執行 - 所以它將無法執行任何與Concrete特定的狀態。有一些非常特定的情況下,這是正確的事情,但他們是罕見的,應該謹慎處理。

你究竟在做什麼?通常我發現有更多的「橫向」鏈條通向一個具有「向上」鏈的構造函數。

+0

謝謝Jon。 getClass知道Object是一個具體事實,但this()調用Abstract no-arg構造器對我來說似乎有點不自然。 我試圖實現的鏈接在我看來似乎允許構造函數之間更自然的責任分工。我想我必須在Concrete的構造函數中複製代碼,或者將它移出到一個新的方法中,但由於我沒有編寫Abstract類的所有具體實現,所以我必須爲其他開發人員編寫文檔。 – 2009-12-07 12:34:15

+1

所以你試圖把構造函數看作是虛擬方法嗎?是的,這是行不通的。 – 2009-12-07 13:06:25

1

這就是它的方式(詳見Jon Skeet)。

您可以添加一個初始化塊,雖然混凝土:

{ 
    Class c = this.getClass(); 
    System.out.println(ORDER++ + ": Class = " 
    + c.getSimpleName() 
    + "; Concrete's init block called."); 
} 

與此相反的默認構造函數,該inizializer塊總是叫:

1: Class = Concrete; Abstract's no-arg constructor called. 
2: Class = Concrete; Abstract's 1-arg constructor called. 
3: Class = Concrete; Concrete's init block called. 
4: Class = Concrete; Concrete's 1-arg constructor called. 
0

處理的最佳方式通常是讓一個類的所有構造函數最終使用一個通用構造函數,即:

public Abstract() { 
    this(null); 
} 
public Abstract(String arg) { 
    // do all Abstract init here 
} 

public Concrete() { 
    this(null); 
} 
public Concrete(String arg) { 
    super(arg); 
    // do all Concrete init here 
} 
1

這裏是一個專注於需要抽象類的,以及它如何works.May這將幫助你的post

1

您應該知道,子類始終對父類隱藏。您不能直接調用子類的方法或構造函數,就像您在子類中所做的那樣。