简体   繁体   中英

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. 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). 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.

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 . This is why heap pollution (inserting the wrong type of object into a generic collection) can result in a ClassCastException at runtime.

Regarding the wildcards:

  • Set<Object> 's generic type is exactly 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.
  • Set<?> has an unspecified generic type. 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.
  • Set , as you mention, is the raw type and shouldn't be used in new code.

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

Generics are implemented by Java compiler as a front-end conversion called erasure. 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.

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. Please have a look.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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