2012-05-04 78 views
5

這似乎是一個基本的Java問題。關於Java子接口子類型

我有一個接口,Pipeline,它有一個方法execute(Stage)

然後,我創建一個子接口,從Pipeline延伸,說BookPipeline,我喜歡的方法是execute(BookStage)

BookStageStage延伸。

似乎這種定義不能通過java編譯。

對此有何建議?

+1

什麼是編譯器錯誤消息?你的代碼是什麼? –

回答

6

你可能要考慮使用泛型。

public interface Pipeline<T extends Stage> { 
    public void execute(T stage); 
} 

public interface BookPipeline extends Pipeline<BookStage> { 
    @Override 
    public void execute(BookStage stage); 
} 
+4

是不是'BookPipline' redudant中'execute'的聲明? –

+0

@KirkWoll是的,這是爲了舉例 – Jeffrey

+0

Gotcha,我不需要重寫它。非常感謝! – BlueDolphin

4

除了@Jeffrey寫作可能的解決方案之外,理解爲什麼你不能做到這一點很重要。

假設您有一個接口Pipeline與方法execute(Stage),並擴展接口BookPipelineexecute(BookStage)

另外假設你有一些類Conc實施BookPipeline

考慮以下

Pipeline p = new Conc(); 
p.execute(new Stage()); 

會發生什麼?這將是不安全的!
Java想要避免它,從而首先防止這種情況。

該規則是擴展類/接口可以添加行爲,但不能減少它

+0

非常好的一點,謝謝! – BlueDolphin

0

只是對@amit的回答闡述,該代碼段是不安全的Conc.execute方法採用BookStage作爲參數,這可能會試圖在地方,要擠Stage(當然,不是所有的Stage s是BookStage s)。

然而,假設我們想要去的其他方式,也就是讓參數類型的BookePipeline.execute超級Stage,如Object

所以我只想澄清,我們將有:

interface Pipeline 
{ 
    void execute(Stage s); 
} 

interface BookPipeline extends Pipeline 
{ 
    @Override 
    void execute(Object s); 
} 

哪裏Conc工具BookPipeline

Pipeline p = new Conc(); 
p.execute(new Stage()); 

因爲Liskov的可替代性,因此沒有違反這在理論上是安全的 - 我們可以安全地將Stage傳遞給參數爲Stage或更大的任何實現。這就是所謂的逆轉。 Java不支持逆變型參數類型,但是有languages那樣做。

你原來的問題涉及到參數類型是不安全的規定的原因(但奇怪的是,語言叫做Eiffel允許這一點)。

然而Java支持協變返回類型。試想Pipeline

Stage getAStage(); 

這將是完全合法BookPipeline重寫此方法像這樣:

@Override 
BookStage getAStage(); 

然後想象我們有:

public void someMethodSomewhere(Pipeline p) 
{ 
    Stage s = p.getAStage(); 
    //do some dance on Stage 
} 

假設我們有一些類Donc其實施Pipeline並且完全按照它在中定義的覆蓋(所以還是返回Stage),這兩個電話都OK:

someMethodSomewhere(new Conc()); 
someMethodSomewhere(new Donc()); 

因爲我們總是可以把一個Stage或任何更小(例如BookStage)在Stage類型的變量中。

所以要改寫規則來具體涉及方法重載,延伸類/接口,它覆蓋的方法,只能讓那些方法在他們接受什麼樣的更普遍在他們返回的內容更加具體(儘管在Java中的情況下,只有更具體的返回類型是允許的。)

只記得,佩奇 - 生產者延伸消費超(約書亞布洛赫,有效的Java)