簡體   English   中英

如何獲取通用類型參數?

[英]How to get the Generic Type Parameter?

只是:

public static class MyClass<T> {
    // i don't want to keep an instance of T, if it is not necessary.
    // and it is not nice, not neat.

    // Or, let's say, the member are in the form of :
    ArrayList<T> mArrayList = new ArrayList<T>();
    // the problem of getting the generic type parameter is still present.
}

@Test
public final void test() {
    MyClass<Integer> myObject = new MyClass<Integer>();
    getParamType( myObject );
}

private static final <T> void getParamType(final MyClass<T> _myObject) {
    System.out.println(_myObject.getClass().getTypeParameters()[0]);    // T
    System.out.println(((T) new Object()).getClass());                  // class java.lang.Object
}

如何讓代碼打印class java.lang.Integer

我知道很多stackoverflow線程正在詢問(和回答)這個問題。 但他們無法解決這個問題。

  • 我不知道為什么有些人需要調用getGenericSuperclass() - 因為在這個簡單的情況下沒有涉及繼承。
  • 我也不能將它轉換為ParameterizedType

System.out.println((ParameterizedType) _myObject.getClass());
// Compile Error: Cannot cast from Class<capture#11-of ? extends TreeTest2.MyClass> to ParameterizedType

System.out.println((ParameterizedType) _myObject.getClass().getGenericSuperclass());
// Runtime Exception: java.lang.ClassCastException

根據@ Thomas的指南,我找到了一種獲取class java.lang.Integer 的解決方法。

首先,我們在測試代碼中創建一個匿名 (它需要是匿名的) MyClass<T>子類。 (這很奇怪。為什么它只支持子類?)

@Test
public final void test() {
    MyClass<Integer> myObject = new MyClass<Integer>() {};  // Anonymous sub-class
    getParamType( myObject );
}

然后我們可以使用getGenericSuperclass()方法獲取一個Type然后將其轉換為ParameterizedType ,然后使用getActualTypeArguments()

private static final <T> void getParamType(final MyClass<T> _myObject) {
    System.out.println( ((ParameterizedType) _myObject.getClass().getGenericSuperclass()).getActualTypeArguments()[0] );
}

它完美地打印class java.lang.Integer

不是很好,因為測試代碼應該模擬實際情況,用戶很可能不會繼續創建無意義的子類。

此方法基於TypeReference類的思想。 但我真的不知道如何使用它。 我嘗試過class MyClass<T> extends TypeReference<T> 但我仍然需要創建MyClass<T>子類,讓TypeReference.getType()打印出class java.lang.Integer

請幫助,並感謝任何輸入,因為最好的方法還沒有。


基於上述解決方法的另一個問題:為什么只有匿名子類有效?

public static class SubMyClass<T> extends MyClass<T>{}

@Test
public final void test() {
    MyClass<Integer> myObject = new MyClass<Integer>() {};  // Anonymous sub-class
    getParamType( myObject );               // class java.lang.Integer

    MyClass<Integer> mySubObject = new SubMyClass<Integer>();   // named sub-class
    getParamType( mySubObject );            // T
}

MyClassgetParamType()不變。)

這有點困難,因為Java故意不能這樣做(“類型擦除”)。

解決方法稱為超類型令牌 SO上也有一些線索(就像這一個那個 )。

當你有這樣的問題時,你應該問問自己,如果沒有泛型,你會怎么做? 因為任何泛型程序都可以轉換為沒有泛型的等效程序。 (這種轉換稱為類型擦除。)因此,如果你不能在沒有泛型的情況下做到這一點,你也無法使用泛型。

你沒有Generics的程序看起來像這樣:

public static class MyClass {
    ArrayList mArrayList = new ArrayList();
}

@Test
public final void test() {
    MyClass myObject = new MyClass();
    Integer result = getParamType( myObject ); // how would you implement getParamType()?
}

Java有一個名為Type Erasure的誤導功能,專門阻止你這樣做。

運行時不存在通用參數信息。

相反,您可以手動接受Class<T>

要了解T的值,您需要通過子類化MyClass在類型定義中捕獲它:

class MyStringClass extends MyClass<String> {}

如果需要,您也可以使用匿名類執行此操作:

MyClass<String> myStringClass = new MyClass<String>{}();

要解析T的值,可以使用TypeTools

Class<?> stringType = TypeResolver.resolveRawArgument(MyClass.class, myStringClass.getClass());
assert stringType == String.class;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM