向接口方法添加额外的类型参数可防止覆盖

时间:2014-11-16 13:43:30

标签: java generics override

以下代码无法编译,这让我感到惊讶。任何人都可以解释原因吗?

Params.java:

public interface Params {
    <E> E test(Class<E> cls);

    interface MoreParams extends Params {
        @Override
        <E, F> E test(Class<E> cls);
    }
}

编译:

Params.java:6: error: name clash: <E#1,F>test(Class<E#1>) in
    MoreParams and <E#2>test(Class<E#2>) in Params have the same
    erasure, yet neither overrides the other
        <E, F> E test(Class<E> cls);
                 ^
  where E#1,F,E#2 are type-variables:
    E#1 extends Object declared in method <E#1,F>test(Class<E#1>)
    F extends Object declared in method <E#1,F>test(Class<E#1>)
    E#2 extends Object declared in method <E#2>test(Class<E#2>)
Params.java:5: error: method does not override or implement a
    method from a supertype
        @Override
        ^
2 errors

如果相关,我使用java-8-oraclejavac版本1.8.0_25

似乎额外的泛型类型参数对类型签名没有实际影响,那为什么它会打破覆盖?

1 个答案:

答案 0 :(得分:1)

我认为这可能与二进制兼容性有关,尽管您获得的确切错误消息可能会令人困惑。

考虑在添加MoreParams接口之前编写的代码:

Params params = new ParamsSubClass();
String str1 = params.test(String.class);
String str2 = params.<>test(String.class);
String str3 = params.<String>test(String.class);

如果您使用类似ParamsSubClass之类的人而不是人工MoreParamsSubClass,那么涉及str1str2的行仍将有效,然而涉及str3的行将不再起作用,因为需要两个类型参数,因此代码不是二进制兼容的。

因此,当您更改类型参数时,您似乎无法覆盖方法,因为这会破坏二进制兼容性。