Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 反射式检查对象是否是方法的有效泛型参数_Java_Generics_Reflection_Type Erasure - Fatal编程技术网

Java 反射式检查对象是否是方法的有效泛型参数

Java 反射式检查对象是否是方法的有效泛型参数,java,generics,reflection,type-erasure,Java,Generics,Reflection,Type Erasure,如何使用反射检查给定对象是否是方法的有效参数(其中参数和对象是泛型类型) 为了了解一些背景知识,我正试图实现以下目标: 在处理反射方法调用时,我认为最好调用所有具有特定类型参数的方法。这适用于原始类型,因为您可以在其类对象上调用isAssignableFrom(Class c)。然而,当你开始在混合中加入泛型时,它突然变得不那么容易了,因为泛型不是反射最初设计的一部分,而且是因为类型擦除 问题更大,但基本上归结为以下几点: 理想溶液 理想情况下,代码 import java.lang.refle

如何使用反射检查给定对象是否是方法的有效参数(其中参数和对象是泛型类型)

为了了解一些背景知识,我正试图实现以下目标:

在处理反射方法调用时,我认为最好调用所有具有特定类型参数的方法。这适用于原始类型,因为您可以在其类对象上调用
isAssignableFrom(Class c)
。然而,当你开始在混合中加入泛型时,它突然变得不那么容易了,因为泛型不是反射最初设计的一部分,而且是因为类型擦除

问题更大,但基本上归结为以下几点:

理想溶液 理想情况下,代码

import java.lang.reflect.*;
import java.util.*;


public class ReflectionAbuse {

    public static void callMeMaybe(List<Integer> number) {
        System.out.println("You called me!");
    }

    public static void callMeAgain(List<? extends Number> number) {
        System.out.println("You called me again!");
    }

    public static void callMeNot(List<Double> number) {
        System.out.println("What's wrong with you?");
    }

    public static <T> void reflectiveCall(List<T> number){
        for(Method method : ReflectionAbuse.class.getDeclaredMethods()) {
            if(method.getName().startsWith("call")) {
                if(canBeParameterOf(method, number)) {
                    try {
                        method.invoke(null, number);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static <T> boolean canBeParameterOf(Method method, List<T> number) {
        // FIXME some checks missing
        return true;
    }

    public static void main(String[] args) {
        reflectiveCall(new ArrayList<Integer>());
    }

}
无论
T
看起来如何,这都应该是可能的(即,它可能是另一种泛型类型,例如
List

显然,这无法工作,因为类型
t
在运行时被擦除且未知

尝试1 我能做的第一件事就是这样:

import java.lang.reflect.*;
import java.util.*;


public class ReflectionAbuse {

            public static void callMeMaybe(ArrayList<Integer> number) {
                System.out.println("You called me!");
            }

            public static void callMeAgain(ArrayList<? extends Number> number) {
                System.out.println("You called me again!");
            }

            public static void callMeNot(ArrayList<Double> number) {
                System.out.println("What's wrong with you?");
            }

    public static <T> void reflectiveCall(List<T> number){
        for(Method method : ReflectionAbuse.class.getDeclaredMethods()) {
            if(method.getName().startsWith("call")) {
                if(canBeParameterOf(method, number)) {
                    try {
                        method.invoke(null, number);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static <T> boolean canBeParameterOf(Method method, List<T> number) {
        return method.getGenericParameterTypes()[0].equals(number.getClass().getGenericSuperclass());
    }

    public static void main(String[] args) {
        reflectiveCall(new ArrayList<Integer>(){});
    }

}
但是,这还有一些额外的注意事项:

  • 它只适用于直接实例,继承层次结构不被考虑,因为
    类型
    接口没有提供所需的方法。这里和那里的演员阵容肯定会有助于找到答案(另请参见我的第二次尝试)
  • reflectiveCall
    的参数实际上需要是所需参数类型的子类(注意
    newarraylist(){}
    中创建匿名内部类的
    {}
    )。这显然不太理想:创建不必要的类对象,并且容易出错。这是我唯一能想到的绕过类型擦除的方法
尝试2 考虑到理想解决方案中由于擦除而丢失的类型,还可以将该类型作为非常接近理想的参数传递:

import java.lang.reflect.*;
import java.util.*;


public class ReflectionAbuse {

    public static void callMeMaybe(List<Integer> number) {
        System.out.println("You called me!");
    }

    public static void callMeAgain(List<? extends Number> number) {
        System.out.println("You called me again!");
    }

    public static void callMeNot(List<Double> number) {
        System.out.println("What's wrong with you?");
    }

    public static <T> void reflectiveCall(List<T> number, Class<T> clazz){
        for(Method method : ReflectionAbuse.class.getDeclaredMethods()) {
            if(method.getName().startsWith("call")) {
                Type n = number.getClass().getGenericSuperclass();
                if(canBeParameterOf(method, clazz)) {
                    try {
                        method.invoke(null, number);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static <T> boolean canBeParameterOf(Method method, Class<T> clazz) {
        Type type = ((ParameterizedType)method.getGenericParameterTypes()[0]).getActualTypeArguments()[0];
        if (type instanceof WildcardType) {
            return ((Class<?>)(((WildcardType) type).getUpperBounds()[0])).isAssignableFrom(clazz);
        }
        return ((Class<?>)type).isAssignableFrom(clazz);
    }

    public static void main(String[] args) {
        reflectiveCall(new ArrayList<Integer>(), Integer.class);
    }

}
import java.lang.reflect.*;
导入java.util.*;
公共类反射总线{
公共静态无效callMeMaybe(列表编号){
System.out.println(“你叫我!”);
}
公共静态无效呼叫增益(列表
我是不是一直在使用匿名子类还是传递类型参数

或多或少,但最好使用该模式进行子类化,而不是对您的值类型进行子类化。毕竟,您的值类型可能不允许子类。使用类型标记模式允许您接受泛型类型,而接受
作为类型参数只允许原始类型(这就是为什么必须采用
列表的组件类型,而不是类型本身)

一旦你有了这个,
canBeParameterOf
就更容易实现了

public static boolean canBeParameterOf(Method method, TypeToken<?> givenType) {
    Type[] argTypes = method.getGenericParameterTypes();

    return argTypes.length != 0 && 
        TypeToken.of(argTypes[0]).isAssignableFrom(givenType);
}
public静态布尔值canBeParameterOf(方法,TypeToken给定类型){
类型[]argTypes=method.getGenericParameterTypes();
返回argTypes.length!=0&&
(argTypes[0])的TypeToken.isAssignableFrom(givenType);
}
相关:
import java.lang.reflect.*;
import java.util.*;


public class ReflectionAbuse {

    public static void callMeMaybe(List<Integer> number) {
        System.out.println("You called me!");
    }

    public static void callMeAgain(List<? extends Number> number) {
        System.out.println("You called me again!");
    }

    public static void callMeNot(List<Double> number) {
        System.out.println("What's wrong with you?");
    }

    public static <T> void reflectiveCall(List<T> number, Class<T> clazz){
        for(Method method : ReflectionAbuse.class.getDeclaredMethods()) {
            if(method.getName().startsWith("call")) {
                Type n = number.getClass().getGenericSuperclass();
                if(canBeParameterOf(method, clazz)) {
                    try {
                        method.invoke(null, number);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static <T> boolean canBeParameterOf(Method method, Class<T> clazz) {
        Type type = ((ParameterizedType)method.getGenericParameterTypes()[0]).getActualTypeArguments()[0];
        if (type instanceof WildcardType) {
            return ((Class<?>)(((WildcardType) type).getUpperBounds()[0])).isAssignableFrom(clazz);
        }
        return ((Class<?>)type).isAssignableFrom(clazz);
    }

    public static void main(String[] args) {
        reflectiveCall(new ArrayList<Integer>(), Integer.class);
    }

}
public static <T> void reflectiveCall(TypeToken<T> type, T value)
reflectiveCall(new TypeToken<List<Integer>>() {}, new ArrayList<Integer>());
public static boolean canBeParameterOf(Method method, TypeToken<?> givenType) {
    Type[] argTypes = method.getGenericParameterTypes();

    return argTypes.length != 0 && 
        TypeToken.of(argTypes[0]).isAssignableFrom(givenType);
}