Java Generics:将原始类型转换为任何可再生类型不会生成未经检查的强制转换警告

时间:2011-10-06 15:51:15

标签: java generics

关于以下代码,我有以下问题:

public class GenericBridgeMethods <T> {

    public static void main(String[] args) {
        List obj = new ArrayList<Integer>();
        List <?> l1 = (List<?>) obj; // clause 1
        GenericBridgeMethods <?> g1 = (GenericBridgeMethods<?>) obj; // clause 2
   }

}

一个。第1条当然不会给出未经检查的投射警告 湾第2条也没有给出未经检查的投射警告

我注意到从原始类型(obj)到ANY可再现类型(如GenericBridgeMethods或GenericBridgeMethods&lt;?&gt;)的强制转换不会给出未经检查的强制转换警告。如果运行此代码,则第2节将发生运行时错误。

编译器不应该在第2条中发出警告

编辑1:

    ArrayList a1 = new ArrayList<Integer>(); // clause 3
    Number n1 = (Number)a1; // clause 4 ERROR
    Comparable c1 = (Comparable)a1; // clause 5

    List l1 = new ArrayList<Integer>(); // clause 6
    Number n2 = (Number)l1; // clause 7
    Comparable c2 = (Comparable)l1; // clause 8

有人能解释为什么只有第4条有错误吗?

1 个答案:

答案 0 :(得分:11)

好吧,首先在GenericBridgeMethods中定义它,T不是可再生类型。可恢复意味着类型将被编码到类中并且将在运行时可用。 T的情况并非如此。

第2条没有给出运行时警告,因为它检查:将有obj类型可分配给GenericBridgeMethods类型的运行时检查。由于您选择了通配符作为类型参数,因此不需要检查T

如果另一方面你做了这样的事情:

GenericBridgeMethods<String> g1 = (GenericBridgeMethods<String>) obj;

为您提供未经检查的分配警告,因为objGenericBridgeMethods String的事实无法在运行时检查。但是,如果您这样做,则会出现相同的警告:

List<String l1 = (List<String>) obj;

修改

如果您对编译器允许您尝试将List强制转换为GenericBridgeMethods的原因感到困惑,那么答案是因为编译器无法知道{{1}的整个层次结构和它的子类。可能有GenericBridgeMethods的子类实现GenericBridgeMethods,在这种情况下,强制转换可能合法。

如果你使List成为最后一个类(因此阻止它有子类),你得到编译错误。在这种情况下,您将收到无法解决的类型错误。

只是为了向您展示您的问题与可再生类型和泛型无关,请看一下:

GenericBridgeMethods

您可以明确地将public static void main(String[] args) { List obj = new ArrayList<Integer>(); //this is allowed (no warning), even though it will fail at runtime CharSequence sequence = (CharSequence) obj; } 投射到obj,即使知道它将在运行时失败。原因是因为所有编译器都知道CharSequenceobj的类型。由于List是一个接口,因此List的实现可能也是CharSequence,因此必须允许强制转换。

每个显式转换都有一定程度的可能性,它可能在运行时失败。否则,它将是一个冗余的强制转换,编译器应该允许你省略显式强制转换。

编辑 - 关于“编辑#1”

List

您想知道为什么只有“第4条”无法编译。我想我已经在上面和评论中对此进行了解释,但我将逐步为您提供这个具体示例。

ArrayList a1 = new ArrayList<Integer>(); // clause 3
Number n1 = (Number)a1; // clause 4 ERROR
Comparable c1 = (Comparable)a1; // clause 5

List l1 = new ArrayList<Integer>(); // clause 6
Number n2 = (Number)l1; // clause 7
Comparable c2 = (Comparable)l1; // clause 8

ArrayList a1 = new ArrayList<Integer>(); // clause 3 Number n1 = (Number)a1; // clause 4 ERROR 投射到a1不起作用,因为NumberNumber都是类,而不是接口。因为Java不允许从多个类继承,所以对象必须是ArrayListNumber的实例,ArrayList必须是Number,反之亦然。众所周知,这在编译时是不正确的。

ArrayList

由于ArrayList a1 = new ArrayList<Integer>(); // clause 3 Comparable c1 = (Comparable)a1; // clause 5 是一个接口,Comparable的子类可能是ArrayList

Comparable

由于List l1 = new ArrayList<Integer>(); // clause 6 Number n2 = (Number)l1; // clause 7 是一个接口,List的子类可以实现Number。编译器不知道何时检查List持有l1的演员表。