Java generics-type erase
I. Overview
Java generics in the use of the process has many problems, such as the absence of List<string>.class, list<integer> can not be assigned to list<number> (non-covariant), Strange classcastexception and so on. Proper use of Java generics requires a deep understanding of some Java concepts, such as covariance, bridging methods, and the type erasure of this note record. The processing of Java generics is almost always done in the compiler, and the compiler-generated bytecode does not contain generic information, and the generic type information is erased in the compilation process, which is the type erase.
Second, how does the compiler handle generics?
Typically, a compiler handles generics in two ways:
1.Code Specialization. A new target code (bytecode or binary code) is generated when instantiating a generic class or generic method. For example, for a generic list, you might need to generate three target codes for string,integer,float.
2.Code sharing. Only one copy of the target code is generated for each generic class, and all instances of the generic class are mapped to this target code, and type checking and type conversion are performed when needed.
Templates (template) in C + + are typical code specialization implementations. The C + + compiler generates a copy of the execution code for each generic class instance. The integer list and string list in the execution code are two different types. This can lead to code bloat, but experienced C + + programmers have the skill to avoid code bloat.
Another disadvantage of Code specialization is that it is a waste of space in a reference type system because the elements in the reference type collection are essentially pointers. There is no need to generate a copy of the execution code for each type. This is the main reason why the Java compiler uses code sharing to handle generics.
The Java compiler creates a unique bytecode representation for each generic type by code sharing, and maps instances of that generic type to this unique bytecode representation. The mapping of multiple generic class instances to a unique bytecode representation is implemented by type Erasue.
Iii. What is type erasure?
Type erasure refers to associating a generic type instance to the same byte code by merging the type parameters. The compiler generates only one byte code for a generic type and associates its instance to this bytecode. The key to type erasure is to clear the information about the type parameter from the generic type and, if necessary, to add methods for type checking and type conversion.
Type erasure can simply be understood as converting generic Java code to plain Java code, except that the compiler is more straightforward and translates generic Java code directly into plain Java bytecode.
The main process for type erasure is as follows:
1. Replace all generic parameters with their leftmost boundary (the top-most parent type) type.
2. Remove all the type parameters.
Such as
Interface comparable <A> {
public int CompareTo (A, that);
}
Final class Numericvalue implements comparable <NumericValue> {
Priva te byte value;
Public Numericvalue (byte value) {this.value = value;}
Public byte GetValue () {return value;}
public int compareTo (Numericvalue t hat) {return this.value-that.value;}
}
-----------------
Class Collections {
public static <a extends Comparable<a>>a max (Collection <A> xs) {
Iterator <A> XI = xs.iterator ();
A w = xi.next ();
while (Xi.hasnext ()) {
A x = Xi.next ();
if (W.compareto (x) < 0) w = x;
}
Return w;
}
}
Final class Test {
public static void Main (string[] args) {
LinkedList <NumericValue> numberlist = new LinkedList <NumericValue> ();
NumberList. Add (New Numericvalue ((byte) 0));
NumberList. Add (New Numericvalue ((byte) 1));
Numericvalue y = Collections.max (numberlist);
}
}
Type erased after type is
Interface Comparable {
public int compareTo (Object);
}
Final class Numericvalue implements comparable {
Priva te byte value;
Public Numericvalue (byte value) {this.value = value;}
Public byte GetValue () {return value;}
public int compareTo (Numericvalue t hat) {return this.value-that.value;}
public int CompareTo (Object this) {return This.compareto ((numericvalue) that); }
}
-------------
Class Collections {
public static comparable Max (Collection xs) {
Iterator XI = Xs.iterator ();
Comparable w = (comparable) xi.next ();
while (Xi.hasnext ()) {
Comparable x = (comparable) xi.next ();
if (W.compareto (x) < 0) w = x;
}
Return w;
}
}
Final class Test {
public static void Main (string[] args) {
LinkedList numberlist = new LinkedList ();
NumberList. Add (New Numericvalue ((byte) 0)); ,
NumberList. Add (New Numericvalue ((byte) 1));
Numericvalue y = (numericvalue) Collections.max (numberlist);
}
}
The first generic class comparable <A> erased after A is replaced with the leftmost bounding object. The comparable<numericvalue> type parameter numericvalue is erased, but this leads directly to Numericvalue not implementing the CompareTo of the interface comparable (Object that) method, the compiler acts as a good person and adds a bridging method.
The second example qualifies the boundary of the type parameter <a extends Comparable<a>>a,a must be a subclass of comparable<a>, and the process of erasing by type, first of all the type parameters TI changes to the leftmost boundary comparable<a>, and then removes the parameter type A to get the final erase result.
Iv. problems caused by type erasure
It is because of the hidden existence of type erasure that it leads directly to many generic supernatural problems.
Q1. Differentiate method signatures with instances of the same generic class? --no!
Import java.util.*;
public class erasure{
public void Test (list<string> ls) {
System.out.println ("Sting");
}
public void Test (list<integer> li) {
System.out.println ("Integer");
}
}
Compile the class,
Parameter type obviously not the same ah, a list<string>, and one is List<integer>, but, secretly, the type erasure after it is a list??
Q2. Catch multiple instances of the same generic exception class at the same time? --no!
Similarly, if a generic class genericexception<t> is defined, don't catch genericexception<integer> and genericexception<string at the same time. , because they are the same drops??
Q3. Static variables for generic classes are shared? --yes!
Guess what the output of this piece of code is?
Import java.util.*;
public class statictest{
public static void Main (string[] args) {
gt<integer> GTI = new gt<integer> ();
Gti.var=1;
gt<string> GTS = new gt<string> ();
gts.var=2;
System.out.println (Gti.var);
}
}
Class gt<t>{
public static int var=0;
public void Nothing (T x) {}
}
The answer is--2!. Because of the type erasure, all generic class instances are associated to the same byte-code, and all static variables of the generic class are shared.
Wu, Just remember
1. There are no generics in the virtual machine, only ordinary classes and common methods
2. All generic class type parameters will be erased at compile time
3. When creating a generic object, indicate the type and let the compiler do the parameter check as early as possible (effective Java, 23rd: Do not use the original ecological type in the new code)
4. Do not ignore compiler warning messages, which means that potential classcastexception are waiting for you.
Java Type Erase