[ad_1]
Java で型の名前を取得するには、 getTypeName
型のクラスに対する関数。 たとえば、次のコード行は次のようになります。
System.out.println(String.class.getTypeName());
印刷されます:
java.lang.String
ただし、ジェネリック型を扱う場合、次のコード行はコンパイルされません ( T
はジェネリック型です):
T.class.getTypeName()
ジェネリック型のクラスを取得する (そしてそこから型の名前を取得する) 方法はありますか?
たとえば、次のクラスがあるとします。
package tries1; public class Person { // ... }
そして次の汎用クラス:
class MyGenericClass<T> { public String getParameterTypeName() { // Here is the place where we should get the generic type (T) name. } }
次のコード:
MyGenericClass<Person> g = new MyGenericClass<>();
System.out.println(g.getParameterTypeName());
印刷する必要があります:
tries1.Person
ジェネリック型のクラス (取得したいもの) もジェネリック型のインスタンスもありません (したがって、呼び出すことができません) getClass
インスタンス上)。
何か案が?
私が試したこと:
インターネットで解決策を検索しましたが、役立つものが見つかりませんでした。
こちらも使ってみました ParameterizedType
ここで説明されているように: https://farizfadian.blogspot.com/2020/02/get-class-name-from-generic-java-class.html[^]:
class MyGenericClass<T> { public String getParameterTypeName() { return ((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()). getActualTypeArguments()[0]).getTypeName(); } }
しかし、次のような例外が発生しました。class java.lang.Class cannot be cast to class java.lang.reflect.ParameterizedType (java.lang.Class and java.lang.reflect.ParameterizedType are in module java.base of loader 'bootstrap')
」。
次のように派生クラスから呼び出したとき:
class MyGenericClass<T> { class MyDerivedFromGeneric extends MyGenericClass<T> { public String getParameterTypeName() { return getParameterTypeNameImpl(); } } public String getParameterTypeName() { MyDerivedFromGeneric dg = new MyDerivedFromGeneric(); return dg.getParameterTypeName(); } protected String getParameterTypeNameImpl() { return ((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()). getActualTypeArguments()[0]).getTypeName(); } }
次のような例外が発生しました:class sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to class java.lang.Class (sun.reflect.generics.reflectiveObjects.TypeVariableImpl and java.lang.Class are in module java.base of loader 'bootstrap')
」。
キャストを外したところ、 Class<T>
:
protected String getParameterTypeNameImpl() { return ((ParameterizedType) getClass().getGenericSuperclass()). getActualTypeArguments()[0].getTypeName(); }
印刷されます:
T
(ない tries1.Person
予想通り。)
私が試したもう 1 つの方向は、定義されたフィールドでリフレクションを使用することです。
class MyGenericClass<T> { public T t1; public String getParameterTypeName() { try { var thisClass = getClass(); var t1Field = thisClass.getField("t1"); var t1Type = t1Field.getType(); return t1Type.getTypeName(); } catch (Exception e) { e.printStackTrace(); } return null; } }
ただし、次のように出力されます。
java.lang.Object
(繰り返しますが、そうではありません tries1.Person
予想通り。)
解決策 2
により タイプ消去、コンパイラはジェネリック型 (T
) の最初の境界 (Object
私たちの場合には)。 したがって、定義された汎用フィールドの型を取得しようとすると、次の結果が得られました。 Object
(そうではない Person
私の期待通りに)。
したがって、ジェネリック宣言だけからジェネリックパラメータの実際の型を取得することは不可能のようです。 ジェネリック パラメーターの実際の型が必要な場合は、別の方法でそれをクラスに注入する必要があります (例: コンストラクター パラメーター、実際の型を返す抽象関数など)。
解決策 1
これらの呼び出しは、生成されたクラスの実際のオブジェクトに対してのみ機能することがわかると思います。 コンパイル時に、 T
prefix には値はなく、コンパイラの単なるマーカーです。 見る クラス (Java プラットフォーム SE 8)[^] 利用可能なオプションについては。
[ad_2]
コメント