简体   繁体   English

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

[英]how the type information is retrieved in generics (Erasure) in Java?

by using generics, we detect any possible during compilation. 通过使用泛型,我们可以在编译过程中检测到任何可能的情况。 for example, 例如,

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

when we use raw type instead of generics before Java 1.5, it needs explicit casting. 当我们在Java 1.5之前使用原始类型而不是泛型时,它需要显式转换。 for example, 例如,

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

however with generics, type erasure occurs. 但是,对于泛型,会发生类型擦除。 that is the type information is lost in runtime. 即类型信息在运行时丢失。 if, that is so, how does the JVM know what object type it is retrieving during runtime, whether it is a string object or a person object (compiler generated cast above). 如果是这样,那么JVM如何知道运行时正在检索的对象类型,无论是字符串对象还是人员对象(上面生成的编译器)。 but this valid with generics, which is can cause runtime errors. 但这对泛型有效,可能会导致运行时错误。

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

finally, Joshua Bloch mentions on page 115 (item 23, effective java) that Set<Object> is parameterized type representing a set that can contain objects of any type, Set<?> is a wild card type representing a set that can contain only objects of some unknown type and Set is a raw type, which opts out of the generic type system. 最后,约书亚·布洛赫(Joshua Bloch)在第115页(有效Java,项目23)中提到Set<Object>是参数化类型,表示可以包含任何类型的对象的Set<?>Set<?>是通配符类型,表示只能包含任何类型的对象某些未知类型的对象,而Set是原始类型,它选择退出通用类型系统。

I do understand what he means by the above statement. 我确实理解上述声明的意思。 some clarifications will help 一些澄清会有所帮助

The compiler inserts cast operations when retrieving items from generic methods; 从通用方法中检索项目时,编译器将插入强制转换操作。 this is the only way that the JVM knows to treat the result of list.get(0) as a String . 这是JVM知道将list.get(0)的结果视为String的唯一方法。 This is why heap pollution (inserting the wrong type of object into a generic collection) can result in a ClassCastException at runtime. 这就是为什么堆污染(将错误类型的对象插入通用集合中)会在运行时导致ClassCastException的原因。

Regarding the wildcards: 关于通配符:

  • Set<Object> 's generic type is exactly Object . Set<Object>的通用类型恰好是Object You can insert and retrieve Object instances from it, but you can't pass a Set<Integer> to a method expecting a Set<Object> , since the method might be planning to add a non- Integer object to the set. 您可以从中插入和检索Object实例,但是不能将Set<Integer>传递给需要Set<Object>的方法,因为该方法可能打算将非Integer对象添加到集合中。
  • Set<?> has an unspecified generic type. Set<?>具有未指定的泛型类型。 A method can retrieve anything from it as an Object (since everything is an Object ) and can call universal methods on it like hashCode or toString , but it can't add anything to the set. 方法可以将任何内容作为Object检索(因为所有内容都是Object ),并且可以像hashCodetoString一样在其上调用通用方法,但不能向集合中添加任何内容。
  • Set , as you mention, is the raw type and shouldn't be used in new code. 正如您提到的, Set是原始类型,不应在新代码中使用。

I am not very sure, but what I understand by type information is lost at runtime is that there is no way at runtime that a collection is of some specific type . 我不太确定,但是我在运行时丢失类型信息,这是因为在运行时 无法确定某个特定类型的集合 If you add a String to a collection, it will be a String only but the collection does not enforce that all elements should be of type String 如果将String添加到集合中,则它将仅是String但是集合不会强制所有元素都应为String类型

Generics are implemented by Java compiler as a front-end conversion called erasure. Java编译器将泛型实现为称为“擦除”的前端转换。 Type erasure applies to the use of generics. 类型擦除适用于泛型的使用。 When generics are used, they're converted into compile time checks and run time type casts . 使用泛型时,它们将转换为编译时检查和运行时类型强制转换

Due to type erasure mechanism this code: 由于类型擦除机制,此代码:

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

gets compiled into this: 被编译成这样:

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

Notice extra cast inserted into compiled compiled-code after type erasure. 请注意,类型擦除后,额外的强制类型转换会插入到已编译的编译代码中。

PS: @chrylis has already provided good explanation about your 2nd part of question. PS:@chrylis已经为您的第二部分问题提供了很好的解释。

Well, this stackoverflow question here can help you . 好了,这个计算器的问题在这里可以帮助你。

Eclipse might be using this method to find out the fields in a class and their generic type if any. Eclipse可能正在使用此方法来查找类中的字段及其通用类型(如果有)。 Please have a look. 请看一看。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM