Java泛型何时在运行时使用转换?

我正在阅读有关C模板和C#泛型的讨论,以及它们与 Java类型擦除泛型的不同之处.我读了一条声明说Java仍然在运行时使用转换,例如在处理集合时.如果这是真的,我不知道它!

假设我有以下代码

ArrayList<SomeClass> list = new ArrayList<SomeClass>();
...
SomeClass object = list.get(0);

我的问题是.这是否有效编译

ArrayList list = new ArrayList();
...
SomeClass object = (SomeClass) list.get(0);

如果是这样,为什么?我认为列表的类型是ArrayList< SomeClass>在编译时和运行时保证只有SomeClass存储在ArrayList中?或者你可以做不安全的类型转换来转换ArrayList< OtherClass>到ArrayList< SomeClass>?

是否有其他场合在Java泛型中进行运行时类型转换?

最后,如果确实使用了在运行时进行的转换,那么JIT是否可以忽略运行时转换检查?

(请不要回答/评论微观优化是不值得的,先发制人的优化是万恶之源等等.我在其他类似的问题上看到了这些.这些点很好理解,但它们并没有带走尝试点了解如何在引擎盖下实现类型擦除的泛型.)

解决方法

这是我写的一个简短的程序:
public class Test<T> {

  public T contents;

  public Test(T item) {
    contents = item;
  }

  public static void main(String[] args) {

    Test<String> t = new Test<String>("hello");
    System.out.println(t.contents);

  }

}

尝试用javac编译它,然后用javap -verbose查看字节码.我选择了几条有趣的线条:

public java.lang.Object contents;

这应该在Test构造函数的定义之前出现.在示例代码中,它是T类型,现在它是一个Object.这是擦除.

现在,看一下主要方法

public static void main(java.lang.String[]);
Code:
   Stack=3,Locals=2,Args_size=1
   0:   new #3; //class Test
   3:   dup
   4:   ldc #4; //String hello
   6:   invokespecial   #5; //Method "<init>":(Ljava/lang/Object;)V
   9:   astore_1
   10:  getstatic   #6; //Field java/lang/System.out:Ljava/io/PrintStream;
   13:  aload_1
   14:  getfield    #2; //Field contents:Ljava/lang/Object;
   17:  checkcast   #7; //class java/lang/String
   20:  invokevirtual   #8; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   23:  return

然后我们可以在第17行看到checkcast命令,就在println之前 – 这是Java从Object转换为擦除的泛型类型的字符串 – String

相关文章

ArrayList简介:ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增...
一、进程与线程 进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。 线程...
本文为博客园作者所写:&#160;一寸HUI,个人博客地址:https://www.cnblogs.com/zsql/ 简单的一个类...
#############java面向对象详解#############1、面向对象基本概念2、类与对象3、类和对象的定义格式4、...
一、什么是异常? 异常就是有异于常态,和正常情况不一样,有错误出错。在java中,阻止当前方法或作用域...
Collection接口 Collection接口 Collection接口 Collection是最基本的集合接口,一个Collection代表一组...