Java汎用でのタイプ消去
Javaコンパイラは汎用コードをコンパイルするときにタイプ消去をしました.パラメトリックの場合、タイプ消去は汎用タイプを上限タイプに変換し、上限がない場合はObjectタイプに変換します.複数の上限タイプがある場合は、一番左の上限タイプに変わります.実パラメータの場合、タイプ消去は汎用情報を削除します.例:
タイプ消去後のコードは次のとおりです.
T task 1=>Callable task 1,パラメータのタイプは消去し,左端タイプ,leftmost bound,汎用タイプは上限タイプに変換した.
class X&Runnable>=>class Xは、実パラメータのタイプが消去され、Xのインスタンスを作成する際には、汎用情報はありません.
http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#Topic3
How does the compiler translate Java generics?
By creating one unique byte code representation of each generic type (or method) and mapping all instantiations of the generic type (or method) to this unique representation.
The Java compiler is responsible for translating Java source code that contains definitions and usages of generic types and methods into Java byte code that the virtual machine can interpret. How does that translation work?
A compiler that must translate a generic type or method (in any language, not just Java) has in principle two choices:
Code specialization. The compiler generates a new representation for every instantiation of a generic type or method. For instance, the compiler would generate code for a list of integers and additional, different code for a list of strings, a list of dates, a list of buffers, and so on.
Code sharing. The compiler generates code for only one representation of a generic type or method and maps all the instantiations of the generic type or method to the unique representation, performing type checks and type conversions where needed.
Code specialization is the approach that C++ takes for its templates:
The C++ compiler generates executable code for every instantiation of a template. The downside of code specialization of generic types is its potential for code bloat. A list of integers and a list of strings would be represented in the executable code as two different types. Note that code bloat is not inevitable in C++ and can generally be avoided by an experienced programmer.
Code specialization is particularly wasteful in cases where the elements in a collection are references (or pointers), because all references (or pointers) are of the same size and internally have the same representation. There is no need for generation of mostly identical code for a list of references to integers and a list of references to strings. Both lists could internally be represented by a list of references to any type of object. The compiler just has to add a couple of casts whenever these references are passed in and out of the generic type or method. Since in Java most types are reference types, it deems natural that Java chooses code sharing as its technique for translation of generic types and methods.
The Java compiler applies the code sharing technique and creates one unique byte code representation of each generic type (or method). The various instantiations of the generic type (or method) are mapped onto this unique representation by a technique that is called type erasure .
LINK TO THIS Technicalities.FAQ100
REFERENCES What is type erasure?
What is type erasure?
A process that maps a parameterized type (or method) to its unique byte code representation by eliding type parameters and arguments.
The compiler generates only one byte code representation of a generic type or method and maps all the instantiations of the generic type or method to the unique representation. This mapping is performed by type erasure. The essence of type erasure is the removal of all information that is related to type parameters and type arguments. In addition, the compiler adds type checks and type conversions where needed and inserts synthetic bridge methods if necessary. It is important to understand type erasure because certain effects related to Java generics are difficult to understand without a proper understanding of the translation process.
The type erasure process can be imagined as a translation from generic Java source code back into regular Java code. In reality the compiler is more efficient and translates directly to Java byte code. But the byte code created is equivalent to the non-generic Java code you will be seeing in the subsequent examples.
The steps performed during type erasure include:
Eliding type parameters.
When the compiler finds the definition of a generic type or method, it removes all occurrences of the type parameters and replaces them by their leftmost bound, or type Object if no bound had been specified.
Eliding type arguments.
When the compiler finds a paramterized type, i.e. an instantiation of a generic type, then it removes the type arguments. For instance, the types List , Set , and Map are translated to List , Set and Map respectively.
Example (before type erasure):
interface Comparable { public int compareTo( A 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; } } class Collections { public static>A max(Collectionxs) { Iteratorxi = 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 numberList = new LinkedList (); numberList .add(new NumericValue((byte)0)); numberList .add(new NumericValue((byte)1)); NumericValue y = Collections.max( numberList ); } } Type parameters are green and type arguments are blue . During type erasure the type arguments are discarded and the type paramters are replaced by their leftmost bound. Example (after type erasure): 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) { LinkedList numberList = new LinkedList(); numberList .add(new NumericValue((byte)0)); numberList .add(new NumericValue((byte)1)); NumericValue y = (NumericValue) Collections.max( numberList ); } } The generic Comparable interface is translated to a non-generic interface and the unbounded type parameter A is replaced by type Object . The NumericValue class implements the non-generic Comparable interface after type erasure, and the compiler adds a so-called bridge method . The bridge method is needed so that class NumericValue remains a class that implements the Comparable interface after type erasure. The generic method max is translated to a non-generic method and the bounded type parameter A is replaced by its leftmost bound, namely Comparable . The parameterized interface Iteratoris translated to the raw type Iterator and the compiler adds a cast whenever an element is retrieved from the raw type Iterator . The uses of the parameterized type LinkedList and the generic max method in the main method are translated to uses of the non-generic type and method and, again, the compiler must add a cast.
class X<T extends Callable<Long> & Runnable> {
private T task1, task2;
...
public void do() {
task1.run();
Long result = task2.call();
}
}
タイプ消去後のコードは次のとおりです.
class X {
private Callable task1, task2;
...
public void do() {
( (Runnable) task1).run();
Long result = (Long) task2.call();
}
}
T task 1=>Callable task 1,パラメータのタイプは消去し,左端タイプ,leftmost bound,汎用タイプは上限タイプに変換した.
class X
http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#Topic3
How does the compiler translate Java generics?
By creating one unique byte code representation of each generic type (or method) and mapping all instantiations of the generic type (or method) to this unique representation.
The Java compiler is responsible for translating Java source code that contains definitions and usages of generic types and methods into Java byte code that the virtual machine can interpret. How does that translation work?
A compiler that must translate a generic type or method (in any language, not just Java) has in principle two choices:
Code specialization. The compiler generates a new representation for every instantiation of a generic type or method. For instance, the compiler would generate code for a list of integers and additional, different code for a list of strings, a list of dates, a list of buffers, and so on.
Code sharing. The compiler generates code for only one representation of a generic type or method and maps all the instantiations of the generic type or method to the unique representation, performing type checks and type conversions where needed.
Code specialization is the approach that C++ takes for its templates:
The C++ compiler generates executable code for every instantiation of a template. The downside of code specialization of generic types is its potential for code bloat. A list of integers and a list of strings would be represented in the executable code as two different types. Note that code bloat is not inevitable in C++ and can generally be avoided by an experienced programmer.
Code specialization is particularly wasteful in cases where the elements in a collection are references (or pointers), because all references (or pointers) are of the same size and internally have the same representation. There is no need for generation of mostly identical code for a list of references to integers and a list of references to strings. Both lists could internally be represented by a list of references to any type of object. The compiler just has to add a couple of casts whenever these references are passed in and out of the generic type or method. Since in Java most types are reference types, it deems natural that Java chooses code sharing as its technique for translation of generic types and methods.
The Java compiler applies the code sharing technique and creates one unique byte code representation of each generic type (or method). The various instantiations of the generic type (or method) are mapped onto this unique representation by a technique that is called type erasure .
LINK TO THIS Technicalities.FAQ100
REFERENCES What is type erasure?
What is type erasure?
A process that maps a parameterized type (or method) to its unique byte code representation by eliding type parameters and arguments.
The compiler generates only one byte code representation of a generic type or method and maps all the instantiations of the generic type or method to the unique representation. This mapping is performed by type erasure. The essence of type erasure is the removal of all information that is related to type parameters and type arguments. In addition, the compiler adds type checks and type conversions where needed and inserts synthetic bridge methods if necessary. It is important to understand type erasure because certain effects related to Java generics are difficult to understand without a proper understanding of the translation process.
The type erasure process can be imagined as a translation from generic Java source code back into regular Java code. In reality the compiler is more efficient and translates directly to Java byte code. But the byte code created is equivalent to the non-generic Java code you will be seeing in the subsequent examples.
The steps performed during type erasure include:
Eliding type parameters.
When the compiler finds the definition of a generic type or method, it removes all occurrences of the type parameters and replaces them by their leftmost bound, or type Object if no bound had been specified.
Eliding type arguments.
When the compiler finds a paramterized type, i.e. an instantiation of a generic type, then it removes the type arguments. For instance, the types List
Example (before type erasure):
interface Comparable { public int compareTo( A 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; } } class Collections { public static>A max(Collectionxs) { Iteratorxi = 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 numberList = new LinkedList (); numberList .add(new NumericValue((byte)0)); numberList .add(new NumericValue((byte)1)); NumericValue y = Collections.max( numberList ); } } Type parameters are green and type arguments are blue . During type erasure the type arguments are discarded and the type paramters are replaced by their leftmost bound. Example (after type erasure): 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) { LinkedList numberList = new LinkedList(); numberList .add(new NumericValue((byte)0)); numberList .add(new NumericValue((byte)1)); NumericValue y = (NumericValue) Collections.max( numberList ); } } The generic Comparable interface is translated to a non-generic interface and the unbounded type parameter A is replaced by type Object . The NumericValue class implements the non-generic Comparable interface after type erasure, and the compiler adds a so-called bridge method . The bridge method is needed so that class NumericValue remains a class that implements the Comparable interface after type erasure. The generic method max is translated to a non-generic method and the bounded type parameter A is replaced by its leftmost bound, namely Comparable . The parameterized interface Iteratoris translated to the raw type Iterator and the compiler adds a cast whenever an element is retrieved from the raw type Iterator . The uses of the parameterized type LinkedList and the generic max method in the main method are translated to uses of the non-generic type and method and, again, the compiler must add a cast.