Infinispanでもうちょっと遊ぶ予定だったのですが、オフィシャルサイトのWikiがなんか途中で落ちてしまったので、別のネタで遊ぶことにしました。
*このネタがだいたい終わった頃には、復旧していましたが…
今回は、パラメータ化された型に関する情報をリフレクションを使ってアクセスしてみようと思います。ちょっと前からやってみたかったのです。
ジェネリクスの情報は、ClassクラスやField、Methodなどからアクセスできるのですが、それぞれ以下のような方法で取得できます。
クラス | メソッド | 取得できる情報 |
Class | getTypeParameters | クラス定義において宣言された型変数の情報 |
Field | getGenericType | フィールドに適用された型変数の情報 |
Constructor | getGenericParameterTypes | コンストラクタのパラメータに関する型変数の情報 |
Constructor | getGenericExceptionTypes | コンストラクタのthrowsに宣言されている、例外に関する型変数の情報 |
Method | getGenericParameterTypes | メソッドのパラメータに関する型変数の情報 |
Method | getGenericReturnType | メソッドの戻り値の型に関する型変数の情報 |
Method | getGenericExceptionTypes | メソッドのthrowsに宣言されている、例外に関する型変数の情報 |
これらのメソッドから取得できるのは、すべてjava.lang.reflect.Typeインターフェースのサブクラス、またはサブインターフェースになります。
クラスまたはインターフェース名 | 意味 | 例 |
java.lang.Class | 普通のClassクラスです | パラメータ化されてないクラス、フィールドなど |
java.lang.reflect.TypeVariable | 型変数自体の情報 | T field、List |
java.lang.reflect.ParameterizedType | パラメータ化された型 | List |
java.lang.reflect.WildcardType | ワイルドカードを持った型 | List<? extends Number>などの<? 〜>の部分 |
java.lang.reflect.GenericArrayType | 型変数情報を使って宣言された配列 | T、List |
上記のインターフェースから、パラメータ化された型に適用された型情報や、型変数を宣言したクラス、ワイルドカードの上限/下限などを取得することができます。
サンプルを作ってみたので、そちらを。
型情報を取得される側のクラス。
class ParameterizedClass<T> { public String nonGeneric; public T field; public T[] array; public List<String> strings; public List<T> list; public List<T>[] listArray; public List<? extends Number> wildUnderNumbers; public List<? super Number> wildUpperNumbers; public <A, B> void m1(A a, B b) { } public <A extends Number> A m2() { return null; }; public <A extends java.io.IOException, B extends RuntimeException> void m3() throws A, B { } public <A> void m4(List<? extends A> list) { } } class NonGeneric extends ParameterizedClass<Object> { } class Actual<String> extends ParameterizedClass<String> { } class ParameterizedClass2<T extends Number> { }
型情報を出力するプログラム。
import java.lang.reflect.*; import java.util.ArrayList; import java.util.List; public class ParameterizedTypeExample { public static void main(String[] args) { try { printf("-------------------- Print ParameterizedClass --------------------%n"); printGenerics(ParameterizedClass.class); printf("-------------------- Print ParameterizedClass --------------------%n"); printf("%n%n"); printf("-------------------- Print nonGeneric --------------------%n"); printGenerics(ParameterizedClass.class.getField("nonGeneric")); printf("-------------------- Print nonGeneric --------------------%n"); printf("%n%n"); printf("-------------------- Print field --------------------%n"); //printf("Field#getType => %s%n", // ParameterizedClass.class.getField("field").getType().getName()); printGenerics(ParameterizedClass.class.getField("field")); printf("-------------------- Print field --------------------%n"); printf("%n%n"); printf("-------------------- Print array --------------------%n"); printGenerics(ParameterizedClass.class.getField("array")); printf("-------------------- Print array --------------------%n"); printf("%n%n"); printf("-------------------- Print strings --------------------%n"); printGenerics(ParameterizedClass.class.getField("strings")); printf("-------------------- Print strings --------------------%n"); printf("%n%n"); printf("-------------------- Print list --------------------%n"); printGenerics(ParameterizedClass.class.getField("list")); printf("-------------------- Print list --------------------%n"); printf("%n%n"); printf("-------------------- Print listArray --------------------%n"); printGenerics(ParameterizedClass.class.getField("listArray")); printf("-------------------- Print listArray --------------------%n"); printf("%n%n"); printf("-------------------- Print wildUnderNumbers --------------------%n"); printGenerics(ParameterizedClass.class.getField("wildUnderNumbers")); printf("-------------------- Print wildUnderNumbers --------------------%n"); printf("%n%n"); printf("-------------------- Print wildUpperNumbers --------------------%n"); printGenerics(ParameterizedClass.class.getField("wildUpperNumbers")); printf("-------------------- Print wildUpperNumbers --------------------%n"); printf("%n%n"); printf("-------------------- Print m1 --------------------%n"); printGenerics(ParameterizedClass.class.getMethod("m1", Object.class, Object.class)); printf("-------------------- Print m1 --------------------%n"); printf("%n%n"); printf("-------------------- Print m2 --------------------%n"); printGenerics(ParameterizedClass.class.getMethod("m2")); printf("-------------------- Print m2 --------------------%n"); printf("%n%n"); printf("-------------------- Print m3 --------------------%n"); printGenerics(ParameterizedClass.class.getMethod("m3")); printf("-------------------- Print m3 --------------------%n"); printf("%n%n"); printf("-------------------- Print m4 --------------------%n"); printGenerics(ParameterizedClass.class.getMethod("m4", List.class)); printf("-------------------- Print m4 --------------------%n"); printf("%n%n"); printf("-------------------- Print NonGenericClass --------------------%n"); printGenerics(NonGeneric.class); printf("-------------------- Print NonGenericClass --------------------%n"); printf("%n%n"); printf("-------------------- Print ActualClass --------------------%n"); printGenerics(Actual.class); printf("-------------------- Print ActualClass --------------------%n"); printf("%n%n"); } catch (NoSuchFieldException | NoSuchMethodException e) { e.printStackTrace(); } } private static void printGenerics(Object target) { if (target instanceof Class) { printf("<<<<< Class#getTypeParameterTypes >>>>>%n"); TypeVariable[] tvs = ((Class<?>)target).getTypeParameters(); if (tvs.length > 0) { for (TypeVariable tv : tvs) { dispatch(tv); } } else { printf("No Parameter Class[%s]%n", target); } } else if (target instanceof Field) { printf("<<<<< Field#getGenericTypes >>>>>%n"); dispatch(((Field)target).getGenericType()); } else if (target instanceof Method) { Method m = (Method)target; Type[] pts = m.getGenericParameterTypes(); printf("<<<<< Method#getGenericParameterTypes >>>>>%n"); for (Type pt : pts) { dispatch(pt); } Type rts = m.getGenericReturnType(); printf("<<<<< Method#getGenericReturnType >>>>>%n"); dispatch(rts); Type[] ets = m.getGenericExceptionTypes(); printf("<<<<< Method#getGenericExceptionTypes >>>>>%n"); for (Type et : ets) { dispatch(et); } } else if (target instanceof Constructor) { Constructor c = (Constructor)target; Type[] pts = c.getGenericParameterTypes(); printf("<<<<< Constructor#getGenericParameterTypes >>>>>%n"); for (Type pt : pts) { dispatch(pt); } Type[] ets = c.getGenericExceptionTypes(); printf("Constructor#getGenericExceptionTypes >>>>>%n"); for (Type et : ets) { dispatch(et); } } else { printf("Unknown Type... [%s]%n", target); } } private static void dispatch(Type type) { if (type instanceof TypeVariable) { printTypeVariables((TypeVariable<?>)type); } else if (type instanceof ParameterizedType) { printParameterizedType((ParameterizedType)type); } else if (type instanceof WildcardType) { printWildcardType((WildcardType)type); } else if (type instanceof GenericArrayType) { printGenericArrayType((GenericArrayType)type); } else if (type instanceof Class) { printf("Class class => %s%n", type); } else { printf("Unkown Type... => %s%n", type); } } private static void printTypeVariables(TypeVariable<?> tv) { printf("TypeVariable#getName => %s%n", tv.getName()); printf("TypeVariable#getGenericDeclaration => %s%n", tv.getGenericDeclaration()); for (Type t : tv.getBounds()) { printf("TypeVariable#getBounds ---->%n"); dispatch(t); } } private static void printParameterizedType(ParameterizedType pt) { printf("ParameterizedType#getOwnerType => %s%n", pt.getOwnerType()); printf("ParameterizedType#getRawType => %s%n", pt.getRawType()); for (Type t : pt.getActualTypeArguments()) { printf("ParameterizedType#getActualTypeArguments ---->%n"); dispatch(t); } } private static void printWildcardType(WildcardType wt) { for (Type t : wt.getLowerBounds()) { printf("WildcardType#getLowerBounds ---->%n"); dispatch(t); } for (Type t : wt.getUpperBounds()) { printf("WildcardType#getUpperBounds ---->%n"); dispatch(t); } } private static void printGenericArrayType(GenericArrayType gat) { printf("GenericArrayType#getGenericComponentType ---->%n"); dispatch(gat.getGenericComponentType()); } private static void printf(String format, Object... args) { System.out.printf(format, args); } }
System.out.printfを書きまくるのがもう面倒だったので、printfとショートカットを作りました…。
プログラムの実行結果と、取得している型情報を並べてみます。
class ParameterizedClass<T>
-------------------- Print ParameterizedClass -------------------- <<<<< Class#getTypeParameterTypes >>>>> TypeVariable#getName => T TypeVariable#getGenericDeclaration => class ParameterizedClass TypeVariable#getBounds ----> Class class => class java.lang.Object -------------------- Print ParameterizedClass --------------------
public String nonGeneric;
-------------------- Print nonGeneric -------------------- <<<<< Field#getGenericTypes >>>>> Class class => class java.lang.String -------------------- Print nonGeneric --------------------
public T field;
-------------------- Print field -------------------- <<<<< Field#getGenericTypes >>>>> TypeVariable#getName => T TypeVariable#getGenericDeclaration => class ParameterizedClass TypeVariable#getBounds ----> Class class => class java.lang.Object -------------------- Print field --------------------
public T[] array;
-------------------- Print array -------------------- <<<<< Field#getGenericTypes >>>>> GenericArrayType#getGenericComponentType ----> TypeVariable#getName => T TypeVariable#getGenericDeclaration => class ParameterizedClass TypeVariable#getBounds ----> Class class => class java.lang.Object -------------------- Print array --------------------
public List<String> strings;
-------------------- Print strings -------------------- <<<<< Field#getGenericTypes >>>>> ParameterizedType#getOwnerType => null ParameterizedType#getRawType => interface java.util.List ParameterizedType#getActualTypeArguments ----> Class class => class java.lang.String -------------------- Print strings --------------------
public List<T> list;
-------------------- Print list -------------------- <<<<< Field#getGenericTypes >>>>> ParameterizedType#getOwnerType => null ParameterizedType#getRawType => interface java.util.List ParameterizedType#getActualTypeArguments ----> TypeVariable#getName => T TypeVariable#getGenericDeclaration => class ParameterizedClass TypeVariable#getBounds ----> Class class => class java.lang.Object -------------------- Print list --------------------
public List<T>[] listArray;
-------------------- Print listArray -------------------- <<<<< Field#getGenericTypes >>>>> GenericArrayType#getGenericComponentType ----> ParameterizedType#getOwnerType => null ParameterizedType#getRawType => interface java.util.List ParameterizedType#getActualTypeArguments ----> TypeVariable#getName => T TypeVariable#getGenericDeclaration => class ParameterizedClass TypeVariable#getBounds ----> Class class => class java.lang.Object -------------------- Print listArray --------------------
public List<? extends Number> wildUnderNumbers;
-------------------- Print wildUnderNumbers -------------------- <<<<< Field#getGenericTypes >>>>> ParameterizedType#getOwnerType => null ParameterizedType#getRawType => interface java.util.List ParameterizedType#getActualTypeArguments ----> WildcardType#getUpperBounds ----> Class class => class java.lang.Number -------------------- Print wildUnderNumbers --------------------
public List<? super Number> wildUpperNumbers;
-------------------- Print wildUpperNumbers -------------------- <<<<< Field#getGenericTypes >>>>> ParameterizedType#getOwnerType => null ParameterizedType#getRawType => interface java.util.List ParameterizedType#getActualTypeArguments ----> WildcardType#getLowerBounds ----> Class class => class java.lang.Number WildcardType#getUpperBounds ----> Class class => class java.lang.Object -------------------- Print wildUpperNumbers --------------------
public <A, B> void m1(A a, B b) { }
-------------------- Print m1 -------------------- <<<<< Method#getGenericParameterTypes >>>>> TypeVariable#getName => A TypeVariable#getGenericDeclaration => public void ParameterizedClass.m1(java.lang.Object,java.lang.Object) TypeVariable#getBounds ----> Class class => class java.lang.Object TypeVariable#getName => B TypeVariable#getGenericDeclaration => public void ParameterizedClass.m1(java.lang.Object,java.lang.Object) TypeVariable#getBounds ----> Class class => class java.lang.Object <<<<< Method#getGenericReturnType >>>>> Class class => void <<<<< Method#getGenericExceptionTypes >>>>> -------------------- Print m1 --------------------
public <A extends Number> A m2() { return null; };
-------------------- Print m2 -------------------- <<<<< Method#getGenericParameterTypes >>>>> <<<<< Method#getGenericReturnType >>>>> TypeVariable#getName => A TypeVariable#getGenericDeclaration => public java.lang.Number ParameterizedClass.m2() TypeVariable#getBounds ----> Class class => class java.lang.Number <<<<< Method#getGenericExceptionTypes >>>>> -------------------- Print m2 --------------------
public <A extends java.io.IOException, B extends RuntimeException> void m3() throws A, B { }
-------------------- Print m3 -------------------- <<<<< Method#getGenericParameterTypes >>>>> <<<<< Method#getGenericReturnType >>>>> Class class => void <<<<< Method#getGenericExceptionTypes >>>>> TypeVariable#getName => A TypeVariable#getGenericDeclaration => public void ParameterizedClass.m3() throws java.io.IOException,java.lang.RuntimeException TypeVariable#getBounds ----> Class class => class java.io.IOException TypeVariable#getName => B TypeVariable#getGenericDeclaration => public void ParameterizedClass.m3() throws java.io.IOException,java.lang.RuntimeException TypeVariable#getBounds ----> Class class => class java.lang.RuntimeException -------------------- Print m3 --------------------
public <A> void m4(List<? extends A> list) { }
-------------------- Print m4 -------------------- <<<<< Method#getGenericParameterTypes >>>>> ParameterizedType#getOwnerType => null ParameterizedType#getRawType => interface java.util.List ParameterizedType#getActualTypeArguments ----> WildcardType#getUpperBounds ----> TypeVariable#getName => A TypeVariable#getGenericDeclaration => public void ParameterizedClass.m4(java.util.List) TypeVariable#getBounds ----> Class class => class java.lang.Object <<<<< Method#getGenericReturnType >>>>> Class class => void <<<<< Method#getGenericExceptionTypes >>>>> -------------------- Print m4 --------------------
class NonGeneric extends ParameterizedClass<Object> { }
-------------------- Print NonGenericClass -------------------- <<<<< Class#getTypeParameterTypes >>>>> No Parameter Class[class NonGeneric] -------------------- Print NonGenericClass --------------------
class Actual<String> extends ParameterizedClass<String> { }
-------------------- Print ActualClass -------------------- <<<<< Class#getTypeParameterTypes >>>>> TypeVariable#getName => String TypeVariable#getGenericDeclaration => class Actual TypeVariable#getBounds ----> Class class => class java.lang.Object -------------------- Print ActualClass --------------------
class ParameterizedClass2<T extends Number> { }
-------------------- Print ParameterizedClass2 -------------------- <<<<< Class#getTypeParameterTypes >>>>> TypeVariable#getName => T TypeVariable#getGenericDeclaration => class ParameterizedClass2 TypeVariable#getBounds ----> Class class => class java.lang.Number -------------------- Print ParameterizedClass2 --------------------
Classクラスはさておき、その他のTypeインターフェースのサブインターフェースのインスタンスが取得できた場合の挙動について、まとめてみましょう。
TypeVariable
getName
型変数が適用されたものに対する、「字面」が取得できます。宣言によって「T」とか「E」とかのこともありますが、たとえ
getGenericDeclaration
型変数を宣言した、クラスやメソッドの情報が取れます。クラスやフィールドだと、その定義が行われたクラス自体、メソッドはそのメソッド自体ですね。
戻り値はGenericDeclarationインターフェースのサブ型となりますが、Class/Constructor/Methodのいずれかになると思われます。
getBounds
型変数に対する上限を表す、Typeの配列が取得できます。
ParameterizedType
getRawType
型情報を適用するように宣言された、Typeを返却します。例えば、List
getActualTypeArguments
この型に対する、型引数Typeの配列が返却されます。どのようなTypeが返却されるかは、型引数の適用方法によって異なります。List
GenericArrayType
getGenericComponentType
配列に適用されたTypeの値が返却されます。ParameterizedType#getActualTypeArgumentsのように、どのような適用のされ方をしたかによって、返却されるTypeのサブ型は異なります。
…と、長かったですがこんなところです。ワイルドカードの上限/下限とかならClassクラスが取得できますが、肝心のTypeVariableからはあくまで「字面」しか取れないところが「う〜ん」ってところですね。
ParameterizedTypeだったらよいのですが。
クラスの宣言自体に使われた、
class Actual<String> extends ParameterizedClass<String> { }
の
パラメータ化された親クラスやインタフェースを使って、型情報を埋め込んだ場合についてはうまくすれば継承や実装時に適用したClassクラスの取得が可能になるようです。
いやぁ、いろいろ勉強になりました。
最後に、コード全体を載せておきます。
ParameterizedTypeExample.java
import java.lang.reflect.*; import java.util.ArrayList; import java.util.List; public class ParameterizedTypeExample { public static void main(String[] args) { try { printf("-------------------- Print ParameterizedClass --------------------%n"); printGenerics(ParameterizedClass.class); printf("-------------------- Print ParameterizedClass --------------------%n"); printf("%n%n"); printf("-------------------- Print nonGeneric --------------------%n"); printGenerics(ParameterizedClass.class.getField("nonGeneric")); printf("-------------------- Print nonGeneric --------------------%n"); printf("%n%n"); printf("-------------------- Print field --------------------%n"); //printf("Field#getType => %s%n", // ParameterizedClass.class.getField("field").getType().getName()); printGenerics(ParameterizedClass.class.getField("field")); printf("-------------------- Print field --------------------%n"); printf("%n%n"); printf("-------------------- Print array --------------------%n"); printGenerics(ParameterizedClass.class.getField("array")); printf("-------------------- Print array --------------------%n"); printf("%n%n"); printf("-------------------- Print strings --------------------%n"); printGenerics(ParameterizedClass.class.getField("strings")); printf("-------------------- Print strings --------------------%n"); printf("%n%n"); printf("-------------------- Print list --------------------%n"); printGenerics(ParameterizedClass.class.getField("list")); printf("-------------------- Print list --------------------%n"); printf("%n%n"); printf("-------------------- Print listArray --------------------%n"); printGenerics(ParameterizedClass.class.getField("listArray")); printf("-------------------- Print listArray --------------------%n"); printf("%n%n"); printf("-------------------- Print wildUnderNumbers --------------------%n"); printGenerics(ParameterizedClass.class.getField("wildUnderNumbers")); printf("-------------------- Print wildUnderNumbers --------------------%n"); printf("%n%n"); printf("-------------------- Print wildUpperNumbers --------------------%n"); printGenerics(ParameterizedClass.class.getField("wildUpperNumbers")); printf("-------------------- Print wildUpperNumbers --------------------%n"); printf("%n%n"); printf("-------------------- Print m1 --------------------%n"); printGenerics(ParameterizedClass.class.getMethod("m1", Object.class, Object.class)); printf("-------------------- Print m1 --------------------%n"); printf("%n%n"); printf("-------------------- Print m2 --------------------%n"); printGenerics(ParameterizedClass.class.getMethod("m2")); printf("-------------------- Print m2 --------------------%n"); printf("%n%n"); printf("-------------------- Print m3 --------------------%n"); printGenerics(ParameterizedClass.class.getMethod("m3")); printf("-------------------- Print m3 --------------------%n"); printf("%n%n"); printf("-------------------- Print m4 --------------------%n"); printGenerics(ParameterizedClass.class.getMethod("m4", List.class)); printf("-------------------- Print m4 --------------------%n"); printf("%n%n"); printf("-------------------- Print NonGenericClass --------------------%n"); printGenerics(NonGeneric.class); printf("-------------------- Print NonGenericClass --------------------%n"); printf("%n%n"); printf("-------------------- Print ActualClass --------------------%n"); printGenerics(Actual.class); printf("-------------------- Print ActualClass --------------------%n"); printf("%n%n"); printf("-------------------- Print ParameterizedClass2 --------------------%n"); printGenerics(ParameterizedClass2.class); printf("-------------------- Print ParameterizedClass2 --------------------%n"); printf("%n%n"); } catch (NoSuchFieldException | NoSuchMethodException e) { e.printStackTrace(); } } private static void printGenerics(Object target) { if (target instanceof Class) { printf("<<<<< Class#getTypeParameterTypes >>>>>%n"); TypeVariable[] tvs = ((Class<?>)target).getTypeParameters(); if (tvs.length > 0) { for (TypeVariable tv : tvs) { dispatch(tv); } } else { printf("No Parameter Class[%s]%n", target); } } else if (target instanceof Field) { printf("<<<<< Field#getGenericTypes >>>>>%n"); dispatch(((Field)target).getGenericType()); } else if (target instanceof Method) { Method m = (Method)target; Type[] pts = m.getGenericParameterTypes(); printf("<<<<< Method#getGenericParameterTypes >>>>>%n"); for (Type pt : pts) { dispatch(pt); } Type rts = m.getGenericReturnType(); printf("<<<<< Method#getGenericReturnType >>>>>%n"); dispatch(rts); Type[] ets = m.getGenericExceptionTypes(); printf("<<<<< Method#getGenericExceptionTypes >>>>>%n"); for (Type et : ets) { dispatch(et); } } else if (target instanceof Constructor) { Constructor c = (Constructor)target; Type[] pts = c.getGenericParameterTypes(); printf("<<<<< Constructor#getGenericParameterTypes >>>>>%n"); for (Type pt : pts) { dispatch(pt); } Type[] ets = c.getGenericExceptionTypes(); printf("Constructor#getGenericExceptionTypes >>>>>%n"); for (Type et : ets) { dispatch(et); } } else { printf("Unknown Type... [%s]%n", target); } } private static void dispatch(Type type) { if (type instanceof TypeVariable) { printTypeVariables((TypeVariable<?>)type); } else if (type instanceof ParameterizedType) { printParameterizedType((ParameterizedType)type); } else if (type instanceof WildcardType) { printWildcardType((WildcardType)type); } else if (type instanceof GenericArrayType) { printGenericArrayType((GenericArrayType)type); } else if (type instanceof Class) { printf("Class class => %s%n", type); } else { printf("Unkown Type... => %s%n", type); } } private static void printTypeVariables(TypeVariable<?> tv) { printf("TypeVariable#getName => %s%n", tv.getName()); printf("TypeVariable#getGenericDeclaration => %s%n", tv.getGenericDeclaration()); for (Type t : tv.getBounds()) { printf("TypeVariable#getBounds ---->%n"); dispatch(t); } } private static void printParameterizedType(ParameterizedType pt) { printf("ParameterizedType#getOwnerType => %s%n", pt.getOwnerType()); printf("ParameterizedType#getRawType => %s%n", pt.getRawType()); for (Type t : pt.getActualTypeArguments()) { printf("ParameterizedType#getActualTypeArguments ---->%n"); dispatch(t); } } private static void printWildcardType(WildcardType wt) { for (Type t : wt.getLowerBounds()) { printf("WildcardType#getLowerBounds ---->%n"); dispatch(t); } for (Type t : wt.getUpperBounds()) { printf("WildcardType#getUpperBounds ---->%n"); dispatch(t); } } private static void printGenericArrayType(GenericArrayType gat) { printf("GenericArrayType#getGenericComponentType ---->%n"); dispatch(gat.getGenericComponentType()); } private static void printf(String format, Object... args) { System.out.printf(format, args); } } class ParameterizedClass<T> { public String nonGeneric; public T field; public T[] array; public List<String> strings; public List<T> list; public List<T>[] listArray; public List<? extends Number> wildUnderNumbers; public List<? super Number> wildUpperNumbers; public <A, B> void m1(A a, B b) { } public <A extends Number> A m2() { return null; }; public <A extends java.io.IOException, B extends RuntimeException> void m3() throws A, B { } public <A> void m4(List<? extends A> list) { } } class NonGeneric extends ParameterizedClass<Object> { } class Actual<String> extends ParameterizedClass<String> { } class ParameterizedClass2<T extends Number> { }