我有一个像这样的简单程序:
package test;
public class TestGenericsInheritance {
public static void main(String[] args) {}
public static abstract class A<Q>{
public void foo2(Q obj){}
public abstract <T> void foo(T obj);
}
public static class C extends A<Object>{
@Override
public <T> void foo(T obj) {}
}
public static class B extends A{
@Override
public <T> void foo(T obj) {}
}
}
如您所见,它什么都不做。在 java 1.6 和 1.7 上编译此程序文件时出现以下错误:
/D:/Projects/.../test/TestGenericsInheritance.java:[24,19] test.TestGenericsInheritance.B is not abstract and do es not override abstract method foo(java.lang.Object) in test.TestGenericsInheritance.A /D:/Projects/.../test/TestGenericsInheritance.java:[27,25] name clash: foo(T) in test.TestGenericsInheritance .B and foo(T) in test.TestGenericsInheritance.A have the same erasure, yet neither overrides the other /D:/Projects/.../test/TestGenericsInheritance.java:[26,9] method does not override or implement a method from a supertype
C 类和 B 类在语义上是相同的,但是 B 类不将方法 foo 识别为 A#foo 的实现。为了使此代码兼容,我必须在类 B 中使用以下签名实现方法 A#foo:
public void foo(Object obj)
我的问题是,为什么我的程序无法编译?泛型 Q 和 T 是完全独立的,那么为什么只有在为继承类 A 显式指定泛型 Q 时才可以实现泛型函数 A#foo?
谢谢
最佳答案
B
扩展原始类型 A
.因为您使用原始类型,所以所有通用信息都将被删除,而不仅仅是您未能指定的类型变量(参见 Section 4.6 of the Java Language Specification )。这意味着 A
有一个方法 void foo(Object obj)
,而 A<SomeType>
有一个方法 <T> void foo(T obj)
.
如果您重写一个方法,它必须具有相同的签名(可选地在对被重写的方法进行类型删除之后)——有趣的是,重写的方法可能具有不同的、更具体的返回类型。您的两种方法的签名不同(您需要在覆盖方法中进行类型删除),因此您的示例无法编译。
按原样实现类型删除的原因是向后兼容。这个想法是新代码只使用泛型,只有旧代码会使用原始类型。因此,目标不是让原始类型最方便(因为无论如何新代码都不应该使用它们),而是让原始类型最兼容。
例如考虑类 ArrayList
,它是在 Java 2 中引入的(远早于泛型)。它有一个方法 public Object[] toArray(Object[] a)
.在 Java 5 中引入了泛型,此方法的签名可以更改为 public <T> T[] toArray(T[] a)
(其中 T
不是元素类型)毫无困难:由于类型删除的实现方式,对于使用(或子类化)ArrayList
的旧代码而不是 ArrayList<SomeType>
方法签名保持不变。
关于Java 泛型 - 使用泛型函数扩展泛型类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38146919/