2011-10-25 77 views
6

我在Java中,下面的例子類:不能直接調用超類型構造函數 - 爲什麼不呢?

public class A { } 

public class Super { 
    protected Super() { } 
    public Super(A a) { } 
} 

public class Sub extends Super { } 

public class Consumer { 
    public Consumer() { 
     Sub sub = new Sub(new A()); //compiler error 
    } 
} 

編譯器錯誤指出的論點不能應用到子默認的構造函數,這是完全可以理解的。

我很好奇這個決定背後的基本原理。 Java在Sub中生成默認的空構造函數;爲什麼不能在這種情況下在幕後調用它?這主要是一個理智的手持情況,還是有技術上的原因?

編輯

我知道這是一個語言的限制。我很好奇爲什麼這是一種語言限制。

EDIT 2

看來,這是常有的情況下,我是太接近我實際工作中看到大圖片的代碼。我在下面的答案中發佈了一個反例,說明爲什麼這是一件壞事。

+0

我在規範中找到的所有東西都是無法完成的。沒有解釋爲什麼http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.2 –

+1

這是Jon Skeet的承擔http://stackoverflow.com/questions/1644317/java -constructor-inheritance/1644410#1644410 –

+1

我對你的編輯感到困惑。你想知道爲什麼當你用一個參數調用構造函數時,沒有參數的默認構造函數不能被調用?顯然,程序員並沒有試圖調用一個完全忽略他的參數的構造函數,否則他不會指定參數! –

回答

2

我認爲這是一個既可讀性又不假定意圖的問題。你說

Java生成默認的空構造函數;爲什麼不能在這種情況下在幕後調用它?

但對我來說,它將使更多的意義for Java來隱式調用構造函數Super(A)「幕後」,而不是調用Super()構造,不顧A

而你有它。在這種情況下,我們已經有了兩個完全不同的假設(或者說可能會發生)。

Java語言的核心原則之一就是透明度。儘可能地,程序員應該能夠通過查看代碼來看看會發生什麼,有時以語法級別的便利性或者魔術爲代價。並行原則並不是假定意圖:在程序員的意圖看起來模糊不清的情況下,Java語言有時會偏向編譯錯誤,而不是通過某些(任意或其他)選擇算法自動選擇缺省值。

+0

好點,但你似乎誤解了我的陳述。我會更新它以使其更清楚。它可能不會改變你的觀點...... – arootbeer

2
public class Sub extends Super { } 

沒有構造函數Sub(A a),它只有默認的構造函數Sub()。

構造函數不被繼承。

+0

構造函數是繼承的,這就是爲什麼它不起作用。 – mikek3332002

+0

@ mikek3332002:我認爲我們只能從子類調用超類構造函數,但不能繼承。 –

0

您已經使用了默認的公共構造函數,所以沒有任何東西需要調用。

因此類子相當於

public class Sub extends Super 
{ 
    protected Sub(){} 
    public Sub(A a) { } 
} 

它會因爲它的

  • 理智的行爲 - 表現爲程序員指定的,而且它也遵循繼承的OOP語言
  • 概念
  • 繼其C++傳統
2

基類需要t o調用超級構造函數以確保對象正確實例化。例如考慮:

class Super { 
    final String field1; 

    public Super(String field1) { 
     this.field1 = field1; 
    } 
    ... 
} 


class Base extends Super { 
    final String field2; 

    public Base(String field2) { 
     this.field2 = field2; 
    } 
    ... 
} 

Base的構造函數重載Super構造?如果是這樣,那麼field1不再保證被初始化,使得繼承的方法意外行爲。

將非默認構造函數添加到子類的那一刻,繼承的構造函數停止工作。我認爲這是一個令人困惑的,很少有用的功能,它被添加到語言中,儘管從技術上看我沒有理由爲什麼它不可能。

+0

這個反例的問題是它不涉及默認的構造函數。你是正確的,這個代碼是有問題的;它甚至不會編譯。不過,我的問題是圍繞默認的構造函數。 – arootbeer

+0

您的示例工作原因是Sub沒有構造函數,如果構造函數僅在這些情況下被繼承,將會是一個令人困惑的功能。 –

+0

我的例子是有問題的,因爲'Sub'沒有構造函數。我會同意你的看法,這會令人困惑,但這個問題是試圖找出爲什麼它會令人困惑。 – arootbeer

0

我把這個作爲這種行爲的技術原因;我同意其他幾個答案,這可能會在語義上混淆。

請看下面的例子:

public class A { } 

public abstract class Super { 
    protected Super() { 
     // perform time consuming, destructive, or 
     // otherwise one-time operations 
    } 

    public Super(A a) { 
     this(); 
     // perform A-related construction operations 
    } 
} 

public class Sub extends Super { } 

public class Consumer { 
    public Consumer() { 
     Sub sub = new Sub(new A()); 
    } 
} 

Sub構造,在這種情況下對Sub默認的構造函數被調用,這將鏈上Super默認構造函數(因爲這是神奇的語言定義)。然後,調用Super(A)將調用在構建時運行一次的邏輯。這顯然不是開發者的意圖。

即使沒有調用Super(A)構造函數中的this(),開發人員的意圖也無法確定;由於某種原因,構造函數可能是互斥的。

相關問題