为什么泛型中未指定的Type会破坏非泛型方法的类型安全

时间:2016-06-08 12:58:15

标签: java generics

有人可以解释一下,为什么我的界面中的简单<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 ....

1 个答案:

答案 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的泛型类型也会被删除。这是应该始终避免原始类型的原因之一。