簡體   English   中英

如何從參數化類型方法參數中獲取參數化類型類?

[英]How can I get the parameterized-type class from a parameterized-type method argument?

考慮這個人為的課程:

import java.util.List;
public class Test {
    public String chooseRandom(List<String> strings) {
        return null;
    }
}

使用反射檢查此方法時,如何在查看chooseRandom的參數時獲取表示java.lang.String (甚至字符串"java.lang.String" )的Class對象?

我知道Java會在編譯時擦除類型,但它們仍然必須存在,因為javap可以正確打印它們。 在此編譯的類上運行javap導致:

Compiled from "Test.java"
public class Test {
  public Test();
  public java.lang.String chooseRandom(java.util.List<java.lang.String>);
}

java.util.Listjava.lang.String )的參數化類型絕對可用......我只是無法找出它是什么。

我試過這個:

Class clazz = [grab the type of chooseRandom's parameter list's first argument];
String typeName = clazz.getName();
TypeVariable[] genericTypes = clazz.getTypeParameters();
if(null != genericTypes && 0 < genericTypes.length)
{
    boolean first = true;
    typeName += "<";
    for(TypeVariable type : genericTypes)
    {
        if(first) first = false;
        else typeName += ",";

        typeName += type.getTypeName();
    }

    typeName = typeName + ">";
}

這給了我一個java.util.List<E>typeName 我希望的是java.util.List<java.lang.String>

我已經在SO上閱讀了其他一些問題和答案,但他們似乎都沒有真正回答這個問題,或者如果他們這樣做,就沒有與之相關的工作代碼,並且解釋很簡單。

使用getGenericParameterTypesgetActualTypeArguments方法:

Method m = Test.class.getMethod("chooseRandom", List.class);
Type t = m.getGenericParameterTypes()[0];
// we know, in this case, that t is a ParameterizedType
ParameterizedType p = (ParameterizedType) t;
Type s = p.getActualTypeArguments()[0]; // class java.lang.String

實際上,如果你不知道至少有一個參數,並且它是通用的並且有一個類型參數,當然,你必須添加一些檢查。

Method.getGenericParameterTypes()將返回泛型參數的ParameterizedType ,可以檢查它以提取其類型參數。 因此, Test.class.getMethod("chooseRandom", List.class).getGenericParameterTypes()應返回包含ParameterizedType的單元素數組。

Java的類型擦除意味着參數( java.util.List )的“真實類型”不包含泛型類型信息。 您不能簡單地使用Method.getParameterTypes()[i]並期望從那里提取泛型參數類型(在本例中為String )。 相反,您必須使用Method.getGenericParameterTypes ,它返回有些無用的java.lang.reflect.Type接口的實現的整個Method.getGenericParameterTypes

最后,這里的代碼提供了一個如何做我試圖做的所有事情的例子:

public String getDataType(Class clazz)
{
    if(clazz.isPrimitive())
        return clazz.getName();

    if(clazz.isArray())
        return getDataType(clazz.getComponentType()) + "[]";

    String typeName;
    if("java.lang".equals(clazz.getPackage().getName()))
        typeName = clazz.getName().substring(10);
    else
        typeName = clazz.getName();

    return typeName;
}

public String getDataType(Type type)
{
    if(type instanceof Class)
        return getDataType((Class)type);

    if(type instanceof ParameterizedType)
    {
        ParameterizedType pt = (ParameterizedType)type;
        StringBuilder typeName = new StringBuilder(getDataType(pt.getRawType()));

        Type[] specificTypes = pt.getActualTypeArguments();
        if(null != specificTypes && 0 < specificTypes.length)
        {
            typeName.append("<");
            for(int j=0; j<specificTypes.length; ++j)
            {
                if(j > 0)
                    typeName.append(",");

                typeName.append(getDataType(specificTypes[j]));
            }

            typeName.append(">");
        }

        return typeName.toString();
    }

    return "[" + type + ", a " + type.getClass().getName() + "]";
}

public void getMethodSignature(Method m)
{
    System.out.print(getDataType(m.getGenericReturnType());
    System.out.print(" ");
    System.out.print(method.getName());
    System.out.print("(");
    Type[] parameterTypes = method.getGenericParameterTypes();
    if(null != parameterTypes && 0 < parameterTypes.length)
    {
        for(int i=0; i<parameterTypes.length; ++i)
        {
            if(0<i) System.out.print(",");
            System.out.print(getDataType(parameterTypes[i]));
        }
    }
    System.out.println(")");
}

我遺漏了簽名中那些不那么令人興奮的部分而且會讓事情變得混亂:可見性和其他標志,異常類型等。

上面的代碼可以正確解碼我試圖檢查的實際方法的類型簽名以獲取更多信息:

protected void parseLocalesHeader(String string,
                                  java.util.TreeMap<Double,java.util.ArrayList<java.util.Locale>> treeMap)

請注意,這當前不處理Type的一些實現,例如TypeVariable (看起來像<T extends Serializable>那個)。 對於那些想跟隨我的腳步的人,我會把它留作練習。 上面的代碼應該可以幫到你。

暫無
暫無

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

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