我今天碰到了这个,我唯一能想到的是这是Java编译器中的一个错误.下面的代码编译,但肯定看起来不正确(因为testMethod在子节点中有一个differenet签名但覆盖了父节点)并且会在运行时抛出类转换异常.
public interface TestInterface<T> {
public List<String> testMethod(); // <-- List<String>
}
public class TestClass implements TestInterface {
@Override
public List<Integer> testMethod() { // <-- List<Integer> overriding List<String>!!
return Collections.singletonList(1);
}
}
Run Code Online (Sandbox Code Playgroud)
并使用以上结构:
public void test() {
TestInterface<Boolean> test = new TestClass();
List<String> strings = test.testMethod();
for (String s : strings) {
System.out.println(s);
}
}
Run Code Online (Sandbox Code Playgroud)
所有这些编译都很好,但是如果运行它会明显抛出类别转换异常.
如果您删除<T>从TestInterface,或填充T在该行中TestClass implements TestInterface<T>,则代码将不再编译,这是有道理的.Imo <T>应该对编译没有影响,testMethod因为它不参与该方法.也许添加<T>到TestInterface导致编译器键入 - 擦除方法签名,即使T不参与这些方法......?
有谁知道这里发生了什么?
如果将泛型类实例化为原始类型,则编译器将忽略其中包含的所有泛型类型参数,因此在编译期间不会给出警告/错误.即宣布
public class TestClass implements TestInterface ...
Run Code Online (Sandbox Code Playgroud)
有效地将代码降级为
public interface TestInterface {
public List testMethod();
}
public class TestClass implements TestInterface {
@Override
public List testMethod() {
return Collections.singletonList(1);
}
}
Run Code Online (Sandbox Code Playgroud)
这确实编译好.
几个星期前发布了类似的问题,其答案表明它不是编译器错误,而是为了向后兼容而进行的深思熟虑的设计决策.