有人可以解释一下,为什么我的界面中的简单<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 ....
答案 0 :(得分:2)
您可以找到答案为section 4.8 of the JLS
未从其超类或超接口继承的原始类型C的构造函数(第8.8节),实例方法(第8.8节,第9.4节)或非静态字段(第8.3节)M的类型是擦除与C对应的泛型声明中的类型。原始类型C的静态成员的类型与对应于C的泛型声明中的类型相同。
如果您创建泛型类的实例而不为其提供泛型类型,则它将变为原始类型。而且,由于JLS的那一部分,所有的(非继承)字段也会被删除。所以就好像你将界面声明为:
interface B{
List listOfStrings();
}
导致您看到的错误。即使您明确指定它,返回的List
的泛型类型也会被删除。这是应该始终避免原始类型的原因之一。