有人可以解释一下,为什么是一个简单的 <T>
我的界面在编译时破坏了类型安全?请参阅以下示例:
public class GenericsMain {
public static void main(String[] args){
A someA = new A() {
@Override
public List<String> listOfStrings() {
return Arrays.asList("A");
}
};
B someB = new B() {
@Override
public List<String> listOfStrings() {
return Arrays.asList("B");
}
};
List<Long> listOfLong = null;
//listOfLong = someA.listOfStrings(); // compile error (expected)
listOfLong = someB.listOfStrings(); // NO COMPILE ERROR. Why !?
for(Long l : listOfLong){ // here I get ClastCastException of course.
System.out.println(l);
}
}
interface A{
List<String> listOfStrings();
}
interface B<T>{
List<String> listOfStrings();
}
}
同样有趣的是,如果 <T>
的类型指定后,编译器会再次正确地提示。所以看起来泛型也会影响非泛型方法声明!?
B<Integer> someBOfInteger = null;
listOfLong = someBOfInteger.listOfStrings(); // compiler complains correctly
正确答案后更新:
因此,如果需要使用泛型扩展类型,最好真正创建一个子类/子接口(interface)并在子类中添加泛型类型。因此,在上面的示例中,可以通过以下方式向 A 添加通用方法
interface C<T> extends A {
T genericMethod(T p);
}
此外,正如所引用的问题所示,使用编译器标志是一个好主意:
javac -Xlint:unchecked ....
最佳答案
你可以找到答案是section 4.8 of the JLS
The type of a constructor (§8.8), instance method (§8.8, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the erasure of its type in the generic declaration corresponding to C. The type of a static member of a raw type C is the same as its type in the generic declaration corresponding to C.
如果您创建泛型类的实例而不为其指定泛型类型,则它会变成原始类型。而且,由于 JLS 的该部分,它的所有(非继承)字段也会被删除。所以就好像您将接口(interface)声明为这样:
interface B{
List listOfStrings();
}
这会导致您看到的错误。即使您显式指定,返回的 List
的通用类型也会被删除。这是应始终避免原始类型的原因之一。
关于java - 为什么泛型中未指定的类型会破坏非泛型方法的类型安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37703206/