2010-07-01 103 views
3

我有下面的代碼:爲什麼java要求構造函數的第一行應該調用父構造函數?如果我們繞過這個要求,有什麼缺陷嗎?

class Foo { 

    public Foo (String param) { ... } 
} 

class Bar extends Foo { 

    public Bar() { 
     super (doSmth()); 
     ... 
    } 

    private static String doSmth() { 
     //what I can NOT do here? 
    } 
} 

我奇怪的是它的安全? doSmth方法有什麼限制嗎?

+0

這是使我討厭繼承的問題之一。 – whiskeysierra 2010-07-01 21:22:36

回答

4

簡單的規則是不直接或間接地從構造函數中訪問「this」對象。

這意味着您不應該從構造函數調用overrideable方法,也不應該調用調用可覆蓋方法的方法,也不應調用調用可覆蓋方法方法的方法,或者...您明白了。

這也意味着你不應該把「this」傳遞給任何東西,因爲另一件事可能會調用一個可覆蓋的方法。

在你的特殊情況下,你有什麼是好的。如果是更改爲:

class Bar extends Foo 
{ 
    public Bar() { 
     super (doSmth(this)); 
     ... 
    } 

    private static String doSmth (Bar bar) { 
     //what I can NOT do here? 
    } 
} 

然後,你將有一個(潛在的)問題,因爲doSmth可以在酒吧依賴於在尚未初始化的數據的子類調用覆蓋方法。

下面是可能發生的事情爲例:

public class Main 
{ 
    public static void main(final String[] argv) 
    { 
     final A a; 

     a = new B(); 
     a.foo(); 
    } 
} 

abstract class A 
{ 
    protected A() 
    { 
     bar(this); 
    } 

    private static void bar(final A a) 
    { 
     a.foo(); 
    } 

    public abstract void foo(); 
} 

class B extends A 
{ 
    final String str; 

    public B() 
    { 
     super(); 
     str = "Hello, World!"; 
    } 

    public void foo() 
    { 
     System.out.println("str - " + str); 
    } 
} 

所以,只要你不叫任何重載方法你都不錯。然而,最簡單的做法是遵循永不傳遞構造函數的「規則」,並且從構造函數直接或間接調用overrideable(非final)方法。

+0

謝謝,非常清楚。 – Roman 2010-07-01 18:29:08

3

繞過這個需求是非常不安全的,因爲它允許你在基類的構造函數運行之前調用一個方法。只有壞事可能發生在那裏。這就是爲什麼Java的(和其他大多數理智的語言迫使該做)

class Foo { 
    string m_field; 
    public Foo(string param) { 
    m_field = param; 
    } 
    public void Method() { 
    // use m_field 
    } 
} 

class Bar extends Foo { 
    public Bar() { 
    // no super 
    Method(); // oops 
    } 
} 
1

有時候,我用它來進行超類的構造函數創建參數。但該方法必須是靜態的:

class MyImplementation extends SuperImplementation { 
    public MyImplementation(String input) { 
     super(convertInput(input)); 
     ... 
    } 

    private static String convertInput (String input) { 
     String output = ""; 
     // do something with input and put it to output 
     return output; 
    } 
} 
3

我沒有看到有人回答您的實際問題尚未...

private static String doSmth() { 
    //what I can NOT do here? 
} 

你可以做任何你想要在那裏。該方法是靜態的,因此您可以訪問所有您想要的字段static。您的編譯器會阻止您嘗試訪問特定於實例的方法/字段。

此外,沒有什麼能夠阻止你使用你的靜態方法在構造函數中,甚至作爲一個先決條件調用一個super()構造:

public Bar() { 
    super (doSmth()); 
    /* ... */ 
} 

...只要doSmth()靜態,你是金。

0

對於問題 爲什麼java要求構造函數的第一行應調用父構造函數?

我相信這是因爲決定時是否注入默認構造函數的java考慮這方面的考慮

class Foo(){ 
abc() 
this() 

} 

可能成爲

class Foo(){ 
this() 
abc() 
this() 

} 

從這裏 http://www.leepoint.net/notes-java/oop/constructors/constructor.html

第一一行構造函數必須是對同一個類中另一個構造函數的調用(使用this)或調用超類的構造函數(使用super)。如果第一行不是這些,編譯器會自動向無參數的超類構造函數插入一個調用。

相關問題