1

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

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)));
    }
}

当然,从 Java 的角度来看,这个错误是完全有道理的;捕获“?”的#1 与“?”的捕获#2无关。但是我们人类可以看到,在这种情况下,使用由 keyType 强制转换的参数调用“apply(…)”是可行的。

是否有可能“愚弄”Java并以某种方式动态应用存储的操作?
使用某种类型的铸造?使用注解?还有其他想法吗?…</p>

4

2 回答 2

2

此问题与通配符捕获的限制有关。通配符本质上就像独立的类型参数一样工作,没有办法表达它们之间的关系。作为一种解决方法,您可以使用“捕获助手”方法,该方法使用实际类型参数来表达这种关系:

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));
}
于 2013-06-25T16:19:22.587 回答
0

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

解决泛型和反射引起的问题……<br/>多使用反射!

给定OperationOperationContainer定义如上使用Class.getMethod(…)and Method.invoke(…)

    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)));

        Operation<?> storedOpp = container.get(keyType);
        try {
            storedOpp.getClass().getMethod("apply", keyType).invoke(storedOpp, keyType.cast(new Integer(5678)));
        } catch (IllegalAccessException | IllegalArgumentException |
                InvocationTargetException | NoSuchMethodException ex) {
            throw new Error(ex);
        }
    }
于 2013-06-25T15:17:44.380 回答