【问题标题】:How and when are variables casted to types declared in generic type parameters?变量如何以及何时转换为泛型类型参数中声明的类型?
【发布时间】:2018-03-30 11:07:09
【问题描述】:
public static void main(String[] args) {

    List<Integer> integers = new ArrayList<>();
    integers.add(5); //element #0

    List list = integers;
    list.add("foo"); //element #1

    integers.get(1); //no error
    System.out.println(integers.get(1)); //no error, prints "foo"
    Integer i = integers.get(1); //throws ClassCastException

}

我试图了解转换类型变量的过程,声明为泛型类型参数,我有点困惑。 因此,您可能会在我提供的示例中看到,在我们创建了一个非参数化的 List,它引用了与 List&lt;Integer&gt; 相同的对象之后,我们可以将任何对象添加到该列表中(好吧,没什么奇怪的这里)而且,让我非常困惑的是,我们可以从List&lt;Integer&gt; integers 中提取非Integer 值。为什么ClassCastException 没有在integers.get(1) 的第一次或第二次调用时抛出?

我假设返回参数类型的方法,实际上总是返回Object,并且那些返回值被隐式尝试转换为 运行时的左值类型或方法参数类型(因为运行时没有泛型),但是以下测试使我确信Integer 总是优于Object

public static void main(String[] args) {

    List<Integer> integers = new ArrayList<>();
    integers.add(5); //element #0

    List list = integers;
    list.add("foo"); //element #1

     print(integers.get(1));

}

private static void print(Object var) {
    System.out.println(var);
}

//this method is entered
private static void print(Integer var) { 
    System.out.println(var);
}

private static void print(String var) {
    System.out.println(var);
}

另一个有趣的事实是,虽然ArrayList 的元素存储在Object[] 数组中,但它们总是在返回到方法get() 之前转换为类型参数中定义的类型:

public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}

E elementData(int index) {
    return (E) elementData[index];
}

所以,如果有人可以向我指出逐步解释这些问题的文档,我将非常感谢

【问题讨论】:

    标签: java generics


    【解决方案1】:

    编译器在需要转换时插入转换。方法System.out.println 有一个Object 类型的参数,因此不需要转换为Integer

    在您的三个print 方法的情况下,选择了带有Integer 类型参数的方法,因此编译器插入了一个强制转换。在编译时根据一组复杂的规则选择使用三种方法中的哪一种。这些规则使用通用信息来查看integers.get(1) 的类型为Integer,因此选择了Integer 版本并且需要转换。结果,代码或多或少等同于Java 4代码

    List integers = new ArrayList();
    integers.add("foo");
    integers.add(Integer.valueOf(5));  // No autoboxing in Java 4!
    print((Integer) integers.get(1));  // Cast inserted by compiler
    

    在您问题的最后部分中对(E) 的强制转换在运行时实际上并没有做任何事情,因此不会抛出ClassCastException。只需要使代码编译即可。您是在告诉编译器,是的,您确定 Object 确实是 E 并且以后不会导致异常(尽管您已经通过混合原始类型和泛型类型来颠覆它)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多