从接口覆盖泛型返回类型

时间:2015-08-07 04:22:31

标签: java generics interface override

我有几个界面:

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,即使接口方法需要Endpoint<T>

2 个答案:

答案 0 :(得分:0)

您的接口方法声明需要一个能够处理任何类型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;
    }
}

答案 1 :(得分:0)

简而言之,第一个因为原始类型而起作用,而接下来的两个因为擦除后方法签名中的冲突而失败。

要获得更长的解释,请记住您的Fetcher::fetch方法是<T extends Fetchable> T fetch(Endpoint<T>),因此Fetcher的实施者必须实施该方法。一个很好的思考方式是Liskov substitution principle,它基本上说是#34;如果你的静态类型是SuperClass,那么它不应该与你拥有的SubClass有关,它们应该只是作为SuperClass工作他们说。&#34;

让我们看看你的第二个两个声明是如何通过想象某人有一个Fetcher并如此调用它来的:

Endpoint<IntFetchable> intEndpoint = whatever();
IntFetchable i = fetcher.fetch(intEndpoint); // T is inferred to be IntFetchable

正如您所看到的那样,为了实现这一目标,fetch方法无法EndpointImplEndpoint<FetchableImpl> - 它确实需要Endpoint<T>

您也可以在方法签名中完全忽略泛型,并使覆盖为原始类型(即类型擦除类型)。这是你用你的第一个覆盖(FetchableImpl fetch(Endpoint))所做的,但原始类型会失去类型安全性并且还有一些其他问题,所以我不推荐它。

如果你想让fetchers专门用于各种端点,你应该采用泛型声明并将其放在Fetcher接口上:

public interface Fetcher<T> {
    T fetch(Endpoint<T> endpoint);
}

现在您可以拥有FetcherImpl implements Fetcher<EndpointImpl>