[英]Overriding generic return type from interface
我有幾個接口:
public interface Endpoint<T extends Fetchable> {
public Class<T> getFetchableType();
}
public interface Fetchable {
... fetched data fields
}
public interface Fetcher {
public <T extends Fetchable> T fetch(Endpoint<T> endpoint);
}
對於實現Fetcher
的類,為什么編譯器使用此方法聲明:
public FetchableImpl fetch(Endpoint endpoint) { return null;}
這些都是錯誤的聲明:
public FetchableImpl fetch(EndpointImpl endpoint) { return null;}
--or--
public FetchableImpl fetch(Endpoint<FetchableImpl> endpoint) { return null;}
其中EndpointImpl implements Endpoint<FetchableImpl>
。
我的直覺是,該參數將具有某種東西,表明它是處理特定類型的Fetchable的端點。 那么,即使接口方法需要Endpoint<T>
時,為什么編譯器也只需要一個直線Endpoint
?
接口方法聲明需要一個能夠處理任何類型的EndPoint
:
public <T extends Fetchable> T fetch(Endpoint<T> endpoint);
但是在您的方法實現中,您可以將其范圍縮小到更特定的EndPoint
類型。
public FetchableImpl fetch(EndpointImpl endpoint) { return null;}
public FetchableImpl fetch(Endpoint<FetchableImpl> endpoint) { return null;}
因此,這些不是接口方法的有效實現。 它們沒有涵蓋接口要求的所有情況。
您可能要聲明一個通用Fetcher
,然后實現該:
public interface Fetcher<T extends Fetchable> {
T fetch(Endpoint<T> endpoint);
}
public class FetcherImpl implements Fetcher<FetchableImpl> {
public FetchableImpl fetch(Endpoint<FetchableImpl> endpoint) {
return null;
}
}
另外,如果你只是想T
的Endpoint<T>
是一樣的T
由該方法返回,你可以保持您的接口方法聲明為是,並在您的實現類使用相同的聲明:
public interface Fetcher {
<T extends Fetchable> T fetch(Endpoint<T> endpoint);
}
public class FetcherImpl implements Fetcher {
public <T extends Fetchable> T fetch(Endpoint<T> endpoint) {
return null;
}
}
簡而言之,第一個起作用的原因是原始類型,而后兩個失敗的原因是擦除后方法簽名的沖突。
對於更長的解釋,請記住Fetcher::fetch
方法是<T extends Fetchable> T fetch(Endpoint<T>)
,因此Fetcher
實現者必須實現該方法。 考慮這一點的一個好方法是Liskov替換原理 ,該原理基本上說:“如果您的靜態類型是SuperClass,那么無論您擁有哪個SubClass都不重要,它們都應該像SuperClass所說的那樣工作。”
讓我們通過想象有人擁有Fetcher
並按如下方式調用它來查看后兩個聲明的Fetcher
:
Endpoint<IntFetchable> intEndpoint = whatever();
IntFetchable i = fetcher.fetch(intEndpoint); // T is inferred to be IntFetchable
如您所見,要使其正常工作, fetch
方法不能采用EndpointImpl
或Endpoint<FetchableImpl>
-它確實需要采用Endpoint<T>
。
您也可以在方法簽名中完全不考慮泛型,而使覆蓋類型為原始類型(即,類型擦除類型)。 這就是您使用第一個重寫( FetchableImpl fetch(Endpoint)
) FetchableImpl fetch(Endpoint)
,但是原始類型失去類型安全性,並且周圍還有一些其他陷阱,因此我不建議這樣做。
如果要使Fetcher
專用於每種端點,則應采用通用聲明並將其放在Fetcher
接口上:
public interface Fetcher<T> {
T fetch(Endpoint<T> endpoint);
}
現在您可以擁有一個FetcherImpl implements Fetcher<EndpointImpl>
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.