2017-02-05 130 views
3

我有下面的代碼示例:Java繼承和方法解析順序

class p { 
    public void druckauftrag() { 
     // ... 
     drucke(); 
    } 

    public void drucke() { 
     System.out.println("B/W-Printer"); 
    } 
} 

class cp extends p { 
    public void drucke() { 
     System.out.println("Color-Printer"); 
    } 
} 

調用下面幾行:

cp colorprinter = new cp(); 
    cp.druckauftrag(); 

還有就是爲什麼「cp.druckauftrag()沒有問題的理解; 「導致控制檯輸出「彩色打印機」。

但是,當我打電話:

p drucker = (p)colorprinter; 
    drucker.druckauftrag(); 

我得到的結果相同 - 爲什麼? 類型轉換是否使用彩色打印機將「drucke」的對象「drucker」的方法「drucke」覆蓋?

在此先感謝您的每一個解釋。

+1

有點挑剔:爲了清晰起見,用大寫字母命名您的類。 –

+1

永遠不要用你的非英語母語,命名類,mehtods等使用英語駝峯時。 –

+0

類的類型是一個定義如何通過'外部用戶'(其他類)看到一個對象。方法實現綁定到一個實例,類型只定義它的外部聯合。 – topr

回答

3

colorprintercp的一個實例。即使你把它轉播到p,它的方法仍然是cp

所不同的是,經過你上溯造型colorprinter,你將無法調用該cp定義了自己的方法。

4

colorprinter不停止是的cp實例當您使用轉換運算符就可以了,所以其實施的public void drucke()不會改變

什麼你與你的(p)colorprinter鑄造表達是什麼樣的您期望對象colorprinter滿足的合同(接口),其中包括具有簽名public void drucke()的公共方法,但不包括任何特定的實現。

而且,順便說一句,這鑄件已隱式執行在聲明的類型pdrucker,所以(p)p drucker = (p)colorprinter;多餘的。 p drucker = colorprinter;就足夠了。

Here you can learn more about typecasting

請記住,最好的做法是從抽象類或接口進行擴展,並且只實現抽象方法。你的代碼更好的設計將是:

abstract class BasePrinter { 

    public void druckauftrag() { 
     // ... 
     drucke(); 
    } 

    public void drucke(); 

} 

class p extends BasePrinter {  
    public void drucke() { 
     System.out.println("B/W-Printer"); 
    } 
} 

class cp extends BasePrinter { 
    public void drucke() { 
     System.out.println("Color-Printer"); 
    } 
} 

但當然約束並不總是允許這種重新設計。通過基部要求參數的構造函數(dependency injection),而不是延伸的基類的也可以是一個很好的選擇:

interface Druckable { 
    void drucke(); 
} 

class Druckauftrager { 

    Druckable dk; 
    Druckauftrager(Drukable dk){ 
     this.dk = dk; 
    } 
    public void druckauftrag() { 
     // ... 
     dk.drucke(); 
    } 

} 

class p implements Druckable {  
    public void drucke() { 
     System.out.println("B/W-Printer"); 
    } 
} 

class cp implements Druckable { 
    public void drucke() { 
     System.out.println("Color-Printer"); 
    } 
} 

現在,如果你想表達的是一臺打印機需要或可以有多種打印功能(像彩色和b/W),你只寫儘可能多的額外Drukable性質和構造函數的參數類,只要你想,例如:

class BlackAndWhiteOrColorPrinter { 

    p blackAndWhitePrintService; 
    cp colorPrintService; 

    Druckable selectedPrintService; 

    BlackAndWhiteOrColorPrinter (p blackAndWhitePrintService, cp colorPrintService){ 
     this.blackAndWhitePrintService = blackAndWhitePrintService; 
     this.colorPrintService = colorPrintService; 
     this.selectedPrintService = blackAndWhitePrintService; 
    } 

    public void druckauftrag() { 
     // ... 
     selectedPrintService.drucke(); 
    } 

} 

這樣,你甚至可以寫一個class MultiPrinterMultiPrinter(List<Druckable> printServices)構造並將任意數量的打印模式添加到其打印服務列表中:pcp,以及其它實施Druckablepublic void drucke()自帶的未來。這也是額外的實際的,如果你想介紹的單元測試,這樣可以提供迫使你要測試,像druke()PaperJamException,例如特定條件樣機的對象。

欲瞭解更多有關如何接口,覆蓋和繼承工作,看到https://docs.oracle.com/javase/tutorial/java/IandI/usinginterface.html

BTW,acording官方java code conventions guide的最新版本,並也被事實上的標準,在Java類應該使用CamelCase命名約定。您也可以極大地從使用semanting命名上所有的定義,像BlackAndWhitePrinter blackAndWhitePrinterColorPrinter colorPrinter受益。

0

當您使用new操作對象,內存heap分配。方法和字段實際上取決於對象的具體實際類別。 改變一個子類覆蓋,並從它的超類修改行爲,調用覆蓋的方法將總是導致修改後的行爲。鑄造只會意味着子類的對象現在由超類型表示,因爲對象具有修改的方法行爲總是會導致修改後的行爲。

假設你有下面的類

public class Fruit{ 
    public void taste(){ 
    System.out.println("depends upon the actual fruit"); 
    } 
} 

public class Mango extends Fruit{ 
    @Override 
    public void taste(){ 
    System.out.println("sweet"); 
    } 
    public void wayToExposeSuperMethod(){ 
    super.taste(); 
    } 
} 

換句話說它就像調用mangofruit,但仍保持mangomango。 對於上面的代碼

Fruit fruit = new Mango(); 

fruit.taste(); // <-- this will output : sweet 

((Mango)fruit).taste();// <-- this will output : sweet 

fruit.wayToExposeSuperMethod(); // <-- this will not compile 

((Mango)fruit).wayToExposeSuperMethod(); // <-- this will output : depends upon the actual fruit