接口的泛化会导致编译错误

时间:2015-10-12 12:54:47

标签: java generics

Java 7

我有一个界面:

public interface MyInt{
    public Map<String, WhereClause> createClauses(Parameters<Object> params);
}

及其实施:

public class MyImpl implements MyInt{

    @Override
    public Map<String, WhereClause> createClauses(Parameters<Object> p) { //1
        //return some
    }
}

现在,我可以将其返回类型设为通用。我试过这个:

public interface MyInt <T extends SomeType>{
    public Map<String, ? extends WhereClause> createClauses(Parameters<Object> params);
}

但是我在//1的实现中遇到了编译时错误:

The method createClauses(Parameters<Object>) of type `MyImpl` must
override or implement a supertype method

但是当我删除Generification时,实现编译得很好。

为什么即使不使用type parameter,泛化也会影响编译。

2 个答案:

答案 0 :(得分:5)

几乎在所有情况下,当你发现自己在泛型中使用?时,你做错了:

public interface MyInt<C extends WhereClause> {

    public Map<String, C> createClauses(Parameters<Object> params);
}

private static class MyWhereClause extends WhereClause {

    public MyWhereClause() {
    }
}

public class MyImpl implements MyInt<MyWhereClause> {

    @Override
    public Map<String, MyWhereClause> createClauses(Parameters<Object> p) {
        return null;
    }
}

答案 1 :(得分:1)

通常,当以主要方式修改界面时,例如,更改其类型参数,如果不重构,则所有子类型应立即中断。

但是有一个例外 - 如果一个接口没有使用任何泛型,我们可以添加泛型并仍然保持以前写的子类型兼容。当然,这是“迁移兼容性”。这是一个奇迹,它运作顺利;像Collection这样的核心API在没有破坏旧程序的情况下被普遍化。 ( - 这是用于保持迁移兼容性的另一种语言"feature"

10年后,这种兼容性功能变得越来越诅咒。您的用例看起来足够合法,但语言根本没有设想这种情况(即之前的非通用接口已经使用了泛型签名),因此这种行为似乎非常令人困惑。还有其他益智游戏(和编译器错误)来自同样的混乱,例如擦除具有非泛型超类型且具有通用方法签名的泛型类型会发生什么。

此时,我们应该忘记这个功能。不要试图泛化非泛型接口(除非你也可以重构子类型)。 尽可能避免使用原始类型。

您可能会引入新类型interface MyInt2<T> extends MyInt,以便MyInt的现有子类型不受影响。