簡體   English   中英

Java Generics:在運行時訪問Generic Type

[英]Java Generics: Accessing Generic Type at runtime

我想在運行時訪問聲明字段的泛型類型。 我之前的印象是,由於Java類型擦除,這是不可能的。 但是,情況並非如此,因為一些眾所周知的框架在運行時通過反射來利用泛型類型。

例如,Guice將根據您提供的泛型類型實現Provider:

public class Injectable{

    @Inject
    private Provider<SomeType> someTypeProvider;

}

如何通過反射API訪問字段的“SomeType”泛型屬性或任何此類類型/方法/等?

此外,了解如何通過Java 6 Annotation Processor API訪問這些泛型類型屬性也很有幫助。

謝謝。

編輯:

謝謝大家的指示。 我找到了一種方法,使用haylem的鏈接,特別是Prenkov的文章Java Reflection:Generics

這是我正在尋找的答案:

/**
 * @author John Ericksen
 */
public class TypeReflectionExample {

    public class SomeType{}

    public class Injectable{
        @Inject  private Provider<SomeType> someTypeProvider;
    }

    public static void main(String[] args){

        try {
            Field providerField = Injectable.class.getDeclaredField("someTypeProvider");

            Type genericFieldType = providerField.getGenericType();

            if(genericFieldType instanceof ParameterizedType){
                ParameterizedType aType = (ParameterizedType) genericFieldType;
                Type[] fieldArgTypes = aType.getActualTypeArguments();
                for(Type fieldArgType : fieldArgTypes){
                    Class fieldArgClass = (Class) fieldArgType;
                    System.out.println("fieldArgClass = " + fieldArgClass);
                }
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }   
}

結果是:

fieldArgClass = class test.TypeReflectionExample $ SomeType

對於Methods,Constructors,Superclass擴展/實現等也可以這樣做

我正在考慮haylem,因為他的帖子引導我解決這個問題,即使它沒有直接回答我的問題。

確實,在Java中運行時通常不知道泛型,因為它們是使用Type Erasure實現的。

反映泛型?

但是,您可以提取一些有關已聲明類型的有價值信息(而不是運行時對象的類型),如Ian Roberston的文章Reflecting Generics和Prenkov的文章Java Reflection:Generics中所述

泛型和類型擦除的背景

引入泛型,同時保留源qnd二進制級別的向后兼容性,因此它們有一些限制,例如:

  • 沒有至少一些仿制葯支持指標(這里是所謂的鑽石操作員 <> )的短手形式是不可能的,
  • 不可能在運行時檢查泛型類型,因為它們必須使用Type Erasure實現。

進一步閱讀

好吧,你為什么不看看guice的作用呢? 來源是公開的。

Guice在多個層面上做這些事情。 特別突出的是類型文字

這里的關鍵點是雖然類型是使用類型擦除編譯的 (因此每種類型只有一個 ),但仍然存在多個Type對象,它們確實知道所使用的泛型。 但是,代碼是獨立優化的(因為它是按類編譯的,而不是每種類型)。

看看ParameterizedType的Java API。

因此,雖然Java Generics在級別上通過“類型擦除”實現是正確的,但這並不完全適用於Type級別。 不幸的是,處理類型比類更棘手。 此外,這也意味着Java無法以與C ++相同的方式優化泛型,特別是對於原始類型。 ArrayList<Integer>將被設計為包含對象的ArrayList<?> ,並且在可能的情況下不由本機int[]數組支持。

但請注意,這與自己跟蹤這些事情非常接近。 說,非常天真(它不適用於嵌套泛型),您可以使用具有字段Class<T> contentClass的類擴展ArrayList<T> ,然后您將能夠在運行時找到此信息。 (盡管如此,TypeLiteral可能是更好的選擇,而不是類!)另外,JRE實際上不能確保列表保持一致。 就像您可以將ArrayList<Integer>轉換為無類型的ArrayList並添加String對象一樣。

我大約一年前就用過這個。 它可以幫助你

Type typeOfSrc = type(YourClass.class, clazz);

// type(C, A1,...,An) => C<A1,...,An>
static ParameterizedType type(final Class raw, final Type... args)
{
    return new ParameterizedType()
    {
        public Type getRawType(){ return raw; }

        public Type[] getActualTypeArguments(){ return args; }

        public Type getOwnerType(){ return null; }
    };
}

這允許您在運行時訪問Generic類型。 基本上你在這里做的是將通用信息存儲在另一個類中,並使用該類在運行時檢索該信息。

我相信guice使用TypeLiteral將通用信息封裝在一個單獨的對象中。

暫無
暫無

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

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