添加Generic允许您覆盖具有不同返回类型的方法?

Mat*_*ogt 8 java generics

我今天碰到了这个,我唯一能想到的是这是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不参与这些方法......?

有谁知道这里发生了什么?

Pét*_*rök 9

如果将泛型类实例化为原始类型,则编译器将忽略其中包含的所有泛型类型参数,因此在编译期间不会给出警告/错误.即宣布

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)

这确实编译好.

几个星期前发布了类似的问题,其答案表明它不是编译器错误,而是为了向后兼容而进行的深思熟虑的设计决策.