2015-09-22 57 views
1

我想獲得類或接口實現的泛型類型。我知道這有一些風險和怪癖,但我試圖理解什麼是可能的。在運行時獲取泛型:在某些情況下有效,但在其他情況下無效 - 爲什麼?

這裏是我的示例代碼:

import java.lang.reflect.ParameterizedType; 
import java.lang.reflect.Type; 
import java.util.Arrays; 
import java.util.LinkedList; 

public class Main { 

    public interface MyInterface<T> { 
    } 

    public static class BaseImpl<T> implements MyInterface<T> { 
    } 

    public static class TypedImpl extends BaseImpl<Integer> { 
    } 

    public static void main(String[] args) throws Exception { 
     LinkedList<MyInterface<Integer>> instances = new LinkedList<>(); 

     // 1. anonymous class from interface 
     instances.add(new MyInterface<Integer>() { 
     }); 

     // 2. class extending interface 
     instances.add(new BaseImpl<Integer>()); 

     // 3. class with pre-defined generic type 
     instances.add(new TypedImpl()); 

     for (MyInterface<Integer> instance : instances) { 
      System.out.println("----------------------------------------------"); 

      Class clazz = instance.getClass(); 
      Type genericSuper = clazz.getGenericSuperclass(); 
      Type[] genericInterfaces = clazz.getGenericInterfaces(); 
      Class target = null; 

      System.out.println("class: " + clazz.getName()); 
      System.out.println("generic super: " + genericSuper); 
      System.out.println("generic interfaces: " + Arrays.asList(genericInterfaces)); 

      // attempt to 'extract' generic type 
      if (genericSuper instanceof ParameterizedType) { 
       target = getGeneric((ParameterizedType) genericSuper); 
      } else if (genericInterfaces.length > 0) { 
       for (Type genericInterface : genericInterfaces) { 
        if (genericInterface instanceof ParameterizedType) { 
         target = getGeneric((ParameterizedType) genericInterface); 

         if (null != target) { 
          break; 
         } 
        } 
       } 
      } 

      System.out.println("TARGET: " + target); 
     } 
    } 

    // attempt to get type argument 
    public static Class getGeneric(ParameterizedType type) { 
     if (MyInterface.class.isAssignableFrom((Class) type.getRawType())) { 
      Type typeArg = type.getActualTypeArguments()[0]; 

      try { 
       return (Class) typeArg; 
      } catch (ClassCastException e) { 
       System.out.println("cast exception for '" + typeArg + "'"); 
      } 
     } 

     return null; 
    } 

} 

的這個輸出是:

---------------------------------------------- 
class: Main$1 
generic super: class java.lang.Object 
generic interfaces: [Main.Main$MyInterface<java.lang.Integer>] 
TARGET: class java.lang.Integer 
---------------------------------------------- 
class: Main$BaseImpl 
generic super: class java.lang.Object 
generic interfaces: [Main.Main$MyInterface<T>] 
cast exception for 'T' 
TARGET: null 
---------------------------------------------- 
class: Main$TypedImpl 
generic super: Main.Main$BaseImpl<java.lang.Integer> 
generic interfaces: [] 
TARGET: class java.lang.Integer 

所以,我的目標是讓target變量的值是Integer.class。對於匿名類(#1)和顯式類型實現(#3),我能夠按預期找到目標。爲什麼它在這些情況下工作,而不是在#2(BaseImpl實例)的情況下工作?有沒有另外一種方法來完成這個? (我知道通過實現類的構造函數傳遞目標Class共同解決方法的,但我感興趣的是動態做這個)

我已經諮詢了以下來源:

非常感謝提前,

阿貝爾

+0

你似乎在尋找http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/ResolvableType解釋。 HTML – EpicPandaForce

回答

0

http://tutorials.jenkov.com/java-reflection/generics.html(加粗是礦)

使用Java泛型通常分爲兩種不同的 一個情況

聲明一個類/接口爲參數化。使用 可參數化的類。當你編寫一個類或接口時,你可以指定它應該是可參數化的。這與java.util.List接口 的情況相同。而不是創建一個對象列表,您可以參數化java.util.List以創建一個說String的列表。

當運行時檢查一個參數化類型本身,像 java.util.List的,有沒有知道什麼類型一直 參數來的方式。這是有道理的,因爲類型可以在同一個應用程序中被參數化爲 到各種類型。 但是,當您檢查 聲明使用參數化類型的方法或字段時, 可以在運行時查看參數化類型爲 到的參數類型。總之:

你看不到一個類型本身它是什麼類型參數的 運行,但你可以看到它的領域,它被使用的方法和參數 。換言之,它的具體參數化。

具體案件的頁面

0

在情況1和3中的類型是所述類別Main$1Main$TypedImpl反射數據的一部分,從而可以訪問它。

在情況2中,只有實例數據由於類型擦除而不包含任何類型信息。因此你不能在這裏訪問泛型類型。

爲了進一步解釋:

在運行時,系統不能BaseImpl<Integer> i;之間distguish和我們說BaseImpl<String> s;,即由於類型擦除兩個變量isBaseImpl型。

相反TypedImpl t;已知是TypedImpl類型和使用反射可以提取在extendsimplements語句提供的通用型的。

方面說明,既然你想了解什麼是可能的:

如果要定義BaseImplBaseImpl<T extends Number> implements MyInterface<T>你可以提取上限TBaseImpl類的反射數據,即你」 d能夠知道T必須是Number或子類型(或接口情況下的實現)。

相關問題