有人可以解释一下,为什么<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
因此,如果需要使用泛型扩展类型,则最好真正地创建一个子类/子接口,并在该子类中添加泛型类型。因此,在上面的示例中,可以通过以下方式向A添加通用方法:
interface C<T> extends A {
T genericMethod(T p);
}
同样如所引用的问题所示,使用编译器标志是一个好主意:
javac -Xlint:unchecked ....
您可以找到答案是JLS的4.8节
未从其超类或超接口继承的原始类型C的构造函数(第8.8节),实例方法(第8.8节,第9.4节)或非静态字段(第8.3节)M的类型是对其类型的擦除原始类型C的静态成员的类型与对应于C的泛型声明中的类型相同。
如果创建通用类的实例而没有为其提供通用类型,则该实例将成为原始类型。而且,由于JLS的这一部分,其所有(非继承)字段也都将被擦除。因此,就好像您声明接口是这样的:
interface B{
List listOfStrings();
}
这会导致您看到错误。List
即使您显式指定了返回的泛型类型,该类型也将被擦除。这就是为什么应始终避免使用原始类型的原因之一。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句