これまでの Java Generics に関する私の明らかな誤解は、Type Erasure によってすべての型情報が削除され、実行時に何も残らないというものでした。最近、私は自分自身に尋ねざるを得ないコード フラグメントに遭遇しました。このハックはどのように機能するのでしょうか? 簡単に説明すると、次のようになります。
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public abstract class SuperClass<T> {
private final Type type;
protected SuperClass(){
ParameterizedType parameterizedType =
(ParameterizedType) getClass().getGenericSuperclass();
type = parameterizedType.getActualTypeArguments()[0];
}
public void tellMyType(){
System.out.println("Hi, my type parameter is " + type);
}
}
そして
public class Example {
public static void main(String[] args) {
SuperClass sc = new SuperClass<Integer>(){};
sc.tellMyType();
}
}
メインクラスを実行すると、次のようになりますHi, my type parameter is class java.lang.Integer
。
ここでわかるのは、T の型情報も実行時に利用できるということですが、これは私の当初の理解と矛盾しています。
そこで私の質問は、なぜコンパイラはこれを保持するのかということです。これは何らかの内部 JVM 動作に必要なのでしょうか、それともこの効果について合理的な説明があるのでしょうか。
ベストアンサー1
からhttp://www.artima.com/weblogs/viewpost.jsp?thread=208860:
JVM はジェネリック クラスのインスタンスの実際の型引数を追跡しませんが、ジェネリック クラスのサブクラスの実際の型引数は追跡します。つまり、 new は実行時には
ArrayList<String>()
単なる new ですArrayList()
が、クラスが を拡張する場合ArrayList<String>
、JVM はが の型String
パラメータの実際の型引数であることを認識します。List
あなたの場合、パラメータ化された型の匿名サブクラスを作成しているので、型情報は保持されます。詳細な説明については記事を参照してください。