Java generic-type erasure I. Overview
Java generics have many problems in use, such as list <string>. class, list <integer> cannot be assigned to list <number> (unchangeable), or strange classcastexception. Correct use of Java generics requires a deep understanding of some java concepts, such as the covariant, bridging method, and the type erasure of this note. Almost all Java generic processing is performed in the compiler. the bytecode generated by the compiler does not include generic information. The generic type information will be erased during compilation, this process is type erasure.
Ii. How does the compiler handle generics?
Generally, a compiler can process generics in two ways:
1. Code specialization. A new object code (bytecode or binary code) is generated when a generic class or generic method is instantiated ). For example, for a generic list, three target codes may need to be generated for string, integer, and float.
2. Code sharing. Only one unique target code is generated for each generic class. All instances of this generic class are mapped to this target code, perform type check and type conversion as needed.
Template in C ++ is a typical code specialization implementation. The C ++ compiler generates an Execution code for each generic class instance. In the Execution Code, integer list and string list are two different types. This will lead to code bloat, but experienced C ++ programmers can be skillful to avoid code bloat.
Another drawback of code specialization is that it wastes space in the reference type system, because the elements in the reference type set are essentially a pointer. There is no need to generate an Execution code for each type. This is also the main reason why the Java compiler uses code sharing to process generics.
The Java compiler creates a unique bytecode representation for each generic type through code sharing, and maps all instances of this generic type to this unique bytecode representation. Ing multiple generic class instances to a unique bytecode representation is implemented by type erasue.
3. What is type erasure?
Type erasure refers to the combination of type parameters to associate a generic type instance with the same bytecode. The compiler generates only one bytecode for the generic type and associates its instance with this bytecode. The key to type erasure is to clear the information about the type parameters from the generic type, and add the type check and type conversion methods when necessary.
Type erasure can be simply understood as converting generic Java code into common Java code, but the compiler is more straightforward and directly converting generic Java code into common Java bytecode.
The main process of Type erasure is as follows:
1. Replace all generic parameters with the leftmost boundary (top-level parent type.
2. Remove all type parameters.
For example
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 ){
Counter list <numericvalue> numberlist = new counter list <numericvalue> ();
Numberlist. Add (New numericvalue (byte) 0 ));
Numberlist. Add (New numericvalue (byte) 1 ));
Numericvalue y = collections. Max (numberlist );
}
}
The erased type is
Interface comparable {
Public int compareto (object that );
}
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 that) {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 ){
Counter list numberlist = new counter list ();
Numberlist. Add (New numericvalue (byte) 0 ));,
Numberlist. Add (New numericvalue (byte) 1 ));
Numericvalue y = (numericvalue) collections. Max (numberlist );
}
}
After the first generic class comparable <A> is erased, A is replaced with the leftmost boundary object. The numericvalue of the comparable <numericvalue> type parameter is erased, but this directly causes numericvalue to fail to implement the comparable compareto (object that) method of the interface, so the compiler acts as a good person, added a bridge method.
In the second example, the boundary of the type parameter <A extends comparable <A> A and A must be a subclass of comparable <A>, first, replace all the type parameters Ti with the leftmost boundary comparable <A>, and then remove parameter type A to get the final erased result.
Iv. problems caused by type Erasure
It is precisely because of the hidden existence of Type erasure that many generic flexibility problems are directly caused.
Q1.How to identify a signature using an instance 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 this class,
The parameter types are obviously different. One is list <string> and the other is list <integer>.
Q2.Catch multiple instances of the same generic exception class at the same time? -- No!
Similarly, if you define a generic genericexception class <t>, do not catch genericexception <integer> and genericexception <string> at the same time, because they are identical to each other.
Q3.Are static variables of generic classes shared? -- Yes!
Guess what the output of this 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 instances are associated with the same bytecode, and all static variables of the generic class are shared.
5. Just remember
1. There is no generic type in the VM, and only common classes and methods are available.
2. All type parameters of generic classes are erased during compilation.
3. specify the type when creating a generic object so that the compiler can perform parameter checks as soon as possible (objective Java, article 23rd: Do not use the original type in the new code)
4. Do not ignore the warning information of the compiler, which means that the potential classcastexception is waiting for you.