Java 如何测试方法返回类型是否与列表匹配<;字符串>;

Java 如何测试方法返回类型是否与列表匹配<;字符串>;,java,generics,reflection,Java,Generics,Reflection,测试(使用反射)给定方法(即java.lang.method实例)是否具有可以安全地强制转换为列表的返回类型的最简单方法是什么 考虑一下这个片段: public static class StringList extends ArrayList<String> {} public List<String> method1(); public ArrayList<String> method2(); public StringList method3();

测试(使用反射)给定方法(即java.lang.method实例)是否具有可以安全地强制转换为列表的返回类型的最简单方法是什么

考虑一下这个片段:

public static class StringList extends ArrayList<String> {}

public List<String> method1();
public ArrayList<String> method2();
public StringList method3();
公共静态类StringList扩展了ArrayList{}
公共列表方法1();
公共ArrayList方法2();
公共字符串列表方法3();
所有方法1、2、3均满足要求。对于method1(通过getGenericReturnType(),它返回ParameterizedType的实例)测试它非常容易,但是对于Method2和3,这并不明显。我想,通过遍历所有getGenericSuperclass()和getGenericInterfaces(),我们可以非常接近,但我不知道如何将列表中的TypeVariable(发生在超类接口的某个地方)与实际的类型参数(即,e与字符串匹配的位置)相匹配

或者也许有一种完全不同(更简单)的方式,我忽略了

编辑:对于那些研究它的人来说,这里是方法4,它也满足了要求,并且显示了更多需要调查的案例:

public interface Parametrized<T extends StringList> {
    T method4();
}
公共接口参数化{
T方法4();
}

我尝试了这段代码,它返回了实际的泛型类型类,因此似乎可以检索类型信息。但是,这仅适用于方法1和2。方法3似乎不像海报所假设的那样返回列表类型的字符串,因此失败

public class Main {
/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    try{
        Method m = Main.class.getDeclaredMethod("method1", new Class[]{});
        instanceOf(m, List.class, String.class);
        m = Main.class.getDeclaredMethod("method2", new Class[]{});
        instanceOf(m, List.class, String.class);
        m = Main.class.getDeclaredMethod("method3", new Class[]{});
        instanceOf(m, List.class, String.class);
        m = Main.class.getDeclaredMethod("method4", new Class[]{});
        instanceOf(m, StringList.class);
    }catch(Exception e){
        System.err.println(e.toString());
    }
}

public static boolean instanceOf (
        Method m, 
        Class<?> returnedBaseClass, 
        Class<?> ... genericParameters) {
    System.out.println("Testing method: " + m.getDeclaringClass().getName()+"."+ m.getName());
    boolean instanceOf = false;
    instanceOf = returnedBaseClass.isAssignableFrom(m.getReturnType());
    System.out.println("\tReturn type test succesfull: " + instanceOf + " (expected '"+returnedBaseClass.getName()+"' found '"+m.getReturnType().getName()+"')");
    System.out.print("\tNumber of generic parameters matches: ");
    Type t = m.getGenericReturnType();
    if(t instanceof ParameterizedType){
        ParameterizedType pt = (ParameterizedType)t;
        Type[] actualGenericParameters = pt.getActualTypeArguments();
        instanceOf = instanceOf
            && actualGenericParameters.length == genericParameters.length;
        System.out.println("" + instanceOf + " (expected "+ genericParameters.length +", found " + actualGenericParameters.length+")");
        for (int i = 0; instanceOf && i < genericParameters.length; i++) {
            if (actualGenericParameters[i] instanceof Class) {
                instanceOf = instanceOf
                        && genericParameters[i].isAssignableFrom(
                            (Class) actualGenericParameters[i]);
                System.out.println("\tGeneric parameter no. " + (i+1) + " matches: " + instanceOf + " (expected '"+genericParameters[i].getName()+"' found '"+((Class) actualGenericParameters[i]).getName()+"')");
            } else {
                instanceOf = false;
                System.out.println("\tFailure generic parameter is not a class");
            }
        }
    } else {
        System.out.println("" + true + " 0 parameters");
    }
    return instanceOf;
}
public List<String> method1() {
    return null;
}
public ArrayList<String> method2() {
    return new ArrayList<String>();
}
public StringList method3() {
    return null;
}
public <T extends StringList> T method4() {
    return null;
}
公共类主{
/**
*@param指定命令行参数
*/
公共静态void main(字符串[]args){
试一试{
方法m=Main.class.getDeclaredMethod(“method1”,新类[]{});
instanceOf(m,List.class,String.class);
m=Main.class.getDeclaredMethod(“method2”,新类[]{});
instanceOf(m,List.class,String.class);
m=Main.class.getDeclaredMethod(“method3”,新类[]{});
instanceOf(m,List.class,String.class);
m=Main.class.getDeclaredMethod(“method4”,新类[]{});
instanceOf(m,StringList.class);
}捕获(例外e){
System.err.println(例如toString());
}
}
公共静态布尔实例(
方法m,
类returnedBaseClass,
类…泛型参数){
System.out.println(“测试方法:“+m.getDeclaringClass().getName()+”+m.getName());
布尔instanceOf=false;
instanceOf=returnedBaseClass.isAssignableFrom(m.getReturnType());
System.out.println(“\t返回类型测试成功:“+instanceOf+”(预期“+returnedBaseClass.getName()+”'found“+m.getReturnType().getName()+”)”);
System.out.print(“\t通用参数匹配数:”);
类型t=m.getGenericReturnType();
if(参数化类型的t实例){
参数化类型pt=(参数化类型)t;
类型[]actualGenericParameters=pt.getActualTypeArguments();
instanceOf=instanceOf
&&actualGenericParameters.length==genericParameters.length;
System.out.println(“+instanceOf+”(应为“+genericParameters.length+”,找到“+actualGenericParameters.length+”);
对于(int i=0;instanceOf&&i
这将产生:

Testing method: javaapplication2.Main.method1 Return type test succesfull: true (expected 'java.util.List' found 'java.util.List') Number of generic parameters matches: true (expected 1, found 1) Generic parameter no. 1 matches: true (expected 'java.lang.String' found 'java.lang.String') Testing method: javaapplication2.Main.method2 Return type test succesfull: true (expected 'java.util.List' found 'java.util.ArrayList') Number of generic parameters matches: true (expected 1, found 1) Generic parameter no. 1 matches: true (expected 'java.lang.String' found 'java.lang.String') Testing method: javaapplication2.Main.method3 Return type test succesfull: false (expected 'java.util.List' found 'com.sun.org.apache.xerces.internal.xs.StringList') Number of generic parameters matches: true 0 parameters Testing method: javaapplication2.Main.method4 Return type test succesfull: true (expected 'com.sun.org.apache.xerces.internal.xs.StringList' found 'com.sun.org.apache.xerces.internal.xs.StringList') Number of generic parameters matches: true 0 parameters 测试方法:javaapplication2.Main.method1 返回类型测试成功:true(应为'java.util.List'找到'java.util.List') 通用参数匹配数:true(应为1,找到1) 1号通用参数匹配:true(应为'java.lang.String'找到'java.lang.String') 测试方法:javaapplication2.Main.method2 返回类型测试成功:true(应为'java.util.List'找到'java.util.ArrayList') 通用参数匹配数:true(应为1,找到1) 1号通用参数匹配:true(应为'java.lang.String'找到'java.lang.String') 测试方法:javaapplication2.Main.method3 返回类型测试成功:false(应为'java.util.List'找到'com.sun.org.apache.xerces.internal.xs.StringList') 匹配的通用参数数:真0个参数 测试方法:javaapplication2.Main.method4 返回类型测试成功:true(预期为'com.sun.org.apache.xerces.internal.xs.StringList'找到'com.sun.org.apache.xerces.internal.xs.StringList') 匹配的通用参数数:真0个参数
在java.net论坛上可能会有帮助(尽管我不得不承认我不理解他们所说的一切)。

我认为你已经走上了正确的道路。只要继续使用和getGenericInterface(),直到你开始恢复参数化类型为止

所以基本上:

//For string list
ParameterizedType type = (ParameterizedType)StringList.class.getGenericSuperclass();
System.out.println( type.getActualTypeArguments()[0] );

//for a descendant of string list
Class clazz = (Class)StringListChild.class.getGenericSuperclass();
ParameterizedType type = (ParameterizedType)clazz.getGenericSuperclass();
System.out.println( type.getActualTypeArguments()[0] );

您可能希望构建一些递归的东西来检查这一点,甚至可能在链的上游查找java.util.List。

仅使用java本身提供的工具来解决这一问题确实不容易。有很多特殊情况(嵌套类、类型参数边界等)需要处理。 这就是为什么我编写了一个库来简化泛型类型反射:。我添加了