Java 如何使用运行时类型信息调用泛型方法?

Java 如何使用运行时类型信息调用泛型方法?,java,generics,reflection,Java,Generics,Reflection,我的程序存储映射到接受此类型参数的操作的参数类型。 当使用显式类型检索存储的操作时,使用给定类型的对象作为参数调用操作的方法没有问题。 但是,当使用仅隐式已知的类型时,调用操作的方法会导致错误: public class StoredArgumentTypeProblem { static class Operation<T> { T apply(T arg) { return arg; } } sta

我的程序存储映射到接受此类型参数的操作的参数类型。 当使用显式类型检索存储的操作时,使用给定类型的对象作为参数调用操作的方法没有问题。 但是,当使用仅隐式已知的类型时,调用操作的方法会导致错误:

public class StoredArgumentTypeProblem {
    static class Operation<T> {
        T apply(T arg) {
            return arg;
        }
    }

    static class OperationContainer {
        private Map<Class<?>, Operation<?>> storedOperations = new HashMap<>();
        public <T> void put(Class<T> argType, Operation<T> opp) {
            storedOperations.put(argType, opp);
        }

        public Class<?> getSomeStoredKey() {
            return storedOperations.keySet().iterator().next();
        }

        public <T> Operation<T> get(Class<T> type) {
            // unchecked cast, but should work given restrictions on put.
            return (Operation<T>)storedOperations.get(type);    
        }
    }

    public void test() {
        OperationContainer container = new OperationContainer();
        container.put(Integer.class, new Operation<Integer>());
        container.get(Integer.class).apply(new Integer(1234));

        Class<?> keyType = container.getSomeStoredKey();

        // ERROR: method apply in Operation<T> cannot be applied to given types
        container.get(keyType).apply(keyType.cast(new Integer(5678)));
    }
}
公共类StoredArgumentTypeProblem{
静态类操作{
T应用(T参数){
返回arg;
}
}
静态类操作容器{
private Map>storedOperations=new HashMap();
公共作废put(类argType,操作opp){
存储操作.put(argType,opp);
}
公共类getSomeStoredKey(){
返回storedOperations.keySet().iterator().next();
}
公共操作get(类类型){
//未选中强制转换,但在给定put限制的情况下应该可以工作。
返回(操作)storedOperations.get(类型);
}
}
公开无效测试(){
OperationContainer=新的OperationContainer();
container.put(Integer.class,new Operation());
container.get(Integer.class).apply(新整数(1234));
类keyType=container.getSomeStoredKey();
//错误:操作中的方法apply无法应用于给定类型
container.get(keyType).apply(keyType.cast(新整数(5678));
}
}
当然,从Java的角度来看,这个错误是完全正确的;捕获#1 of‘?’与捕获#2 of‘?’无关。但我们人类可以看到,在这种情况下,使用keyType强制转换的参数调用“apply(…)”是可行的

是否可以“愚弄”Java并以某种方式动态应用存储的操作?

使用某种类型的铸件?使用注释?还有其他想法吗

在写上述问题时,我想到了以下解决方案

要解决泛型和反射引起的问题…
使用更多的反射

给定上述定义的
操作
操作容器
,使用和:

公共无效测试(){
OperationContainer=新的OperationContainer();
container.put(Integer.class,new Operation());
container.get(Integer.class).apply(新整数(1234));
类keyType=container.getSomeStoredKey();
//错误:操作中的方法apply无法应用于给定类型
//container.get(keyType).apply(keyType.cast(新整数(5678));
操作storedOpp=container.get(keyType);
试一试{
getMethod(“apply”,keyType).invoke(storedOpp,keyType.cast(新整数(5678));
}捕获(IllegalAccessException | IllegalArgumentException|
InvocationTargetException | NoSuchMethodException ex){
抛出新错误(ex);
}
}

此问题与通配符捕获的限制有关。通配符的工作原理与独立类型参数类似,无法表示它们之间的关系。作为一种解决方法,您可以使用“capture helper”方法,该方法使用实际的类型参数来表示该关系:

private <T> void apply(
        OperationContainer container,
        Class<T> keyType,
        Object argument
) {
    T castArgument = keyType.cast(argument);
    Operation<T> operation = container.get(keyType);
    operation.apply(castArgument);
}

public void test() {
    OperationContainer container = new OperationContainer();
    container.put(Integer.class, new Operation<Integer>());
    container.get(Integer.class).apply(new Integer(1234));

    Class<?> keyType = container.getSomeStoredKey();

    apply(container, keyType, new Integer(5678));
}
private void应用(
操作容器,
类键类型,
对象参数
) {
T castArgument=keyType.cast(参数);
操作=container.get(keyType);
操作。应用(castArgument);
}
公开无效测试(){
OperationContainer=新的OperationContainer();
container.put(Integer.class,new Operation());
container.get(Integer.class).apply(新整数(1234));
类keyType=container.getSomeStoredKey();
应用(容器、键类型、新整数(5678));
}
private <T> void apply(
        OperationContainer container,
        Class<T> keyType,
        Object argument
) {
    T castArgument = keyType.cast(argument);
    Operation<T> operation = container.get(keyType);
    operation.apply(castArgument);
}

public void test() {
    OperationContainer container = new OperationContainer();
    container.put(Integer.class, new Operation<Integer>());
    container.get(Integer.class).apply(new Integer(1234));

    Class<?> keyType = container.getSomeStoredKey();

    apply(container, keyType, new Integer(5678));
}