当前位置: 首页 > 知识库问答 >
问题:

Java中泛型(擦除)是如何检索类型信息的?

汲昊空
2023-03-14

通过使用泛型,我们可以在编译过程中检测到任何可能的错误。例如

List<String> list = new ArrayList<String>();
//list.add(new Integer(45)); This will cause compilation error.
list.add("car");
list.add("bus");
list.add("bike");
String vehicle = list.get(0); //compiler-generated cast

当我们在Java1.5之前使用原始类型而不是泛型时,它需要显式转换。例如,

List list2 = new ArrayList();
    list.add("car");
    list.add("bus");
    list.add("bike");
    String vehicle = (String)list.get(0); //explicit casting is necessary

然而,对于泛型,会发生类型擦除。也就是说,类型信息在运行时丢失。如果,也就是说,JVM如何知道它在运行时检索的对象类型,是字符串对象还是person对象(上面由编译器生成的cast)。但这对泛型有效,这可能会导致运行时错误。

List<Object> test = new ArrayList<Object>();
            test.add("hello");
            test.add(new Integer(34));

最后,Joshua Bloch在第115页(第23项,有效java)中提到,Set

我确实明白他上述声明的意思。一些澄清将有所帮助


共有3个答案

易淳
2023-03-14

泛型由Java编译器作为称为擦除的前端转换来实现。类型擦除适用于泛型的使用。当使用泛型时,它们被转换为编译时检查和运行时类型转换。

由于类型擦除机制,此代码:

List<String> a = new ArrayList<String>();
a.add("foo");
String x = a.get(0);

编译成:

List a = new ArrayList();
a.add("foo");
String x = (String) a.get(0);

请注意,在类型擦除后,额外的强制转换插入到编译编译代码中。

注:@chrylis已经很好地解释了你问题的第二部分。

柳杰
2023-03-14

我不是很确定,但我所理解的是,在运行时类型信息丢失是因为在运行时,集合不可能是某种特定类型的。如果将字符串添加到集合中,它将仅为字符串,但集合不强制所有元素都应为字符串

国高杰
2023-03-14

编译器在从泛型方法检索项时插入强制转换操作;这是JVM知道的处理list结果的唯一方法。获取(0)作为字符串。这就是为什么堆污染(在泛型集合中插入错误类型的对象)会在运行时导致ClassCastException

关于通配符:

  • Set

 类似资料:
  • 问题内容: 有没有办法检索为Foo的实现而给出的T? 例如, 将返回绿色。 问题答案: 与其他答案相反,您可以获得通用参数的类型。例如,将其添加到通用类内部的方法中,将获得该类的第一个通用参数(在您的情况下): 我在我编写的通用Hibernate DAO中使用了此技术,因此我可以获得持久化的实际类,因为Hibernate需要它。有用!

  • 问题内容: 我是从Joshua Bloch的google I / O困惑者演讲中得到的。这是代码 这个main方法会引发异常,因为它是原始类型,因此in中的所有泛型都将被删除,因此最终调用而不是。 我的问题是,即使我打电话是不是应该把它调用的方法,因为由于类型擦除,这种方法是有效的并且是类型的不是? 问题答案: 被调用的方法是在编译时定义的,而不是在运行时定义的。 如果在构造函数调用中添加参数,则

  • 现在,当我在地图上迭代时…我能以某种方式获得每个Class1对象的类型(K,V)吗??

  • 问题内容: 类型擦除应该擦除所有泛型信息…如果是这种情况,那么像GSON这样的库如何使用泛型来确定反序列化为哪种类型? 例如 这将反序列 化为 将反序列化为 因此以某种方式在运行时使用通用信息。 问题答案: 类型擦除不会擦除所有类型信息。它不会从类,字段,返回类型和参数定义中将其删除。保留以下示例中的类型信息: 这是可以通过反射实现的。您可以检查给定的是否是该类,将其强制转换为该类并获取类型信息。

  • 问题内容: Java泛型中的擦除概念是什么? 问题答案: 基本上,这是通过编译器技巧在Java中实现泛型的方式。编译后的通用代码实际上只使用你谈论的任何地方(或其他一些类型参数),并且有一些元数据告诉编译器它确实是通用类型。 当你针对通用类型或方法编译某些代码时,编译器会弄清你的实际意思(即,类型参数的含义T),并在编译时验证你做对了事情,但是发出的代码再次在讨论就-编译器在必要时生成额外的强制类

  • 我有一个返回泛型的函数: 所以,当我试图匹配一个函数结果时,我的问题是: 我得到一个警告:“类型模式数组[CustomerInfo到[CustomerApplication到]]中的非变量类型参数CustomerApplication-DDTO未选中,因为它已被擦除消除。” 这是否意味着在Array[]中可以得到任何类型的数组?所以我已经阅读了关于ClassTag和TypeTag的文章,但是误解了