2012-10-09 74 views
6

我想要獲得Java中的繼承權,並瞭解到當在子類中重寫方法(和隱藏字段)時,仍然可以從超級類通過使用'超級'關鍵字。訪問未覆蓋的超類方法時使用'超'關鍵字

我想知道的是,'super'關鍵字應該用於非覆蓋方法嗎?

是否有區別(對於未覆蓋的方法/非隱藏的字段)?

我把下面的例子放在一起。

public class Vehicle { 
    private int tyreCost; 

    public Vehicle(int tyreCost) { 
     this.tyreCost = tyreCost; 
    } 

    public int getTyreCost() { 
     return tyreCost; 
    }   
} 

public class Car extends Vehicle { 
    private int wheelCount; 

    public Vehicle(int tyreCost, int wheelCount) { 
     super(tyreCost); 
     this.wheelCount = wheelCount; 
    } 

    public int getTotalTyreReplacementCost() { 
     return getTyreCost() * wheelCount; 
    } 
} 

具體來說,鑑於getTyreCost()還沒有被覆蓋,應該getTotalTyreReplacementCost()使用getTyreCost(),或者super.getTyreCost()

我想知道超級應該用在超類的字段或方法被訪問的所有實例中(在代碼中顯示您正在訪問超類),還是隻在被覆蓋/隱藏的情況下使用(所以它們站出來)。

回答

10

不要使用super關鍵字來引用其他未覆蓋的方法。這讓其他開發人員試圖擴展你的課程變得困惑。

讓我們來看看的一些代碼以這種方式使用super關鍵字。在這裏,我們有2類:DogCleverDog

/* file Dog.java */ 
public static class Dog extends Animal { 

    private String name; 

    public Dog(String name) { 
     this.name = name; 
    } 

    public String getName() { 
     return name; 
    } 

} 

/* file CleverDog.java */ 
public class CleverDog extends Dog { 

    public CleverDog(String name) { 
     super(name); 
    } 

    public void rollover() { 
     System.out.println(super.getName()+" rolls over!"); 
    } 

    public void speak() { 
     System.out.println(super.getName() + " speaks!"); 
    } 

} 

現在,想象一下你在項目中的新開發者,你需要一些具體的行爲一個聰明的狗是誰在電視上:這狗已經做的一切它的伎倆,而應該是以其虛構的電視名稱。要做到這一點,你重寫getName(...)方法...

/* file DogOnTv.java */ 
public class DogOnTv extends CleverDog { 

    String fictionalName; 

    public DogOnTv(String realName, String fictionalName) { 
     super(realName); 
     fictionalName = fictionalName; 
    } 

    public String getName() { 
     return fictionalName; 
    } 

} 

...並落入由原始開發者和他們不同尋常的使用super關鍵字設下的陷阱!

上面的代碼不會起作用 - 因爲在原始的CleverDog實現中,使用super關鍵字調用getName()。這意味着它總是調用Dog.getName() - 與任何重寫無關。因此,當您使用新DogOnTv類型...

System.out.println("Showcasing the Clever Dog!"); 
    CleverDog showDog = new CleverDog("TugBoat"); 
    showDog.rollover(); 
    showDog.speak(); 

    System.out.println("And now the Dog on TV!"); 
    DogOnTv dogOnTv = new DogOnTv("Pal", "Lassie"); 
    dogOnTv.rollover(); 

...你的錯誤輸出:

Showcasing the Clever Dog! 
Tugboat rolls over! 
Tugboat speaks! 

And now the Dog on TV! 
Pal rolls over! 
Pal speaks! 

這不是當你覆蓋的方法通常預期的行爲,所以你應避免使用不屬於的super關鍵字造成這種混淆。

但是,如果這其實是你想要的行爲,使用final關鍵字代替 - 清楚地表明,該方法不能被重寫:

/* file CleverDog.java */ 
public class CleverDog extends Dog { 

    public CleverDog(String name) { 
     super(name); 
    } 

    public final String getName() { // final so it can't be overridden 
     return super.getName(); 
    } 

    public void rollover() { 
     System.out.println(this.getName()+" rolls over!"); // no `super` keyword 
    } 

    public void speak() { 
     System.out.println(this.getName() + " speaks!"); // no `super` keyword 
    } 

} 
-1

建議對繼承類的進一步更改不需要添加超級​​限定符,並且還可以防止錯誤發生時的錯誤。

1

如果您使用super,您明確告訴使用超類方法(不管子類是否有重寫方法),否則首先jvm檢查子類中的方法(如果有,覆蓋方法),如果不可用超類方法。

0

覆蓋意味着在具有相同方法簽名的子類中從超類中重新定義方法。在你的情況下,getTyreCost()方法沒有被覆蓋,你沒有重新定義你的子類的方法,所以沒有必要使用super.getTyreCost(),只有getTyreCost()會做(就像super.getTyreCost()將以同樣的方式)。 super關鍵字用於重寫方法時,並且您希望子類中的方法調用在超類中實現。

3

通過不使用super關鍵字來訪問getTyreCost,您正在做正確的做法。

但是,您應該將您的成員設置爲私人並且只使用getter方法。

使用super關鍵字應該保留給需要顯式調用父方法的構造函數和重載方法。

+0

好去處(這只是我寫了一個例子作爲問題的一部分)。會員現在更新並設置爲私人。 – Jonny

2

這將取決於您打算如何使用代碼。如果您指定super.getTyreCost(),然後重寫該方法。您仍將在超類中調用方法,而不是重寫的版本。

在我看來,調用super可能會導致更多的混淆,所以最好只在明確需要的時候指定。但是,對於您在此處介紹的情況 - 行爲不會有任何差異。

2

這取決於你的需求和你的願望。使用super強制編譯/應用程序忽略當前類中的任何潛在方法。如果你想傳達你只想使用父母的方法,那麼使用super是適當的。它還會阻止將來對您的類進行修改,從而意外地覆蓋父方法,從而破壞您的預期邏輯。

但是,這些情況相當罕見。在班級中隨處使用超級會導致非常混亂的代碼混亂。在大多數情況下,只需在自己的類中調用該方法,並允許編譯器/ jvm確定需要調用哪種方法(超級或本地)就更合適。它還允許您乾淨地覆蓋/修改/操作super的返回值。

0

從技術上講,在這種情況下被調用的是繼承版本,其實現實際上由父類提供。

有些情況下您必須使用super關鍵字。例如如果Car已覆蓋該方法,爲了提供其自身的不同實現,但您需要調用父類提供的實現,那麼您將使用super關鍵字。在這種情況下,您無法忽略關鍵字super,因爲如果您這樣做了,那麼您將調用由子類本身提供的實現。

+0

Downvote?爲什麼?Downvoter,請留意留下評論。可能是我可以學到一些東西。 –

+2

這是我!我覺得「無論是否使用它,它沒有任何區別」都可能會引起誤解,尤其是在繼續嘗試繼承和重寫的情況下。誠然,你用「在這種情況下」來結束這句話,這使得它有點準確 - 但我仍然認爲這可能是誤導/混淆。重新說一句話,我會很高興放棄投票! –

+0

@RichardJPLeGuen:我重新回答了我的回答,並刪除了誤導性部分。如果有什麼東西仍然有誤導性,請讓我知道我會很樂意編輯。 +1的評論。 –