我的程序存储映射到接受此类参数的操作的参数类型。 当使用显式类型来检索存储的操作时,使用给定类型的对象作为参数调用操作的方法是没有问题的。 但是,当使用仅隐式知道的类型时,调用操作的方法会导致错误:
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并以某种方式动态应用存储的操作?
使用某种类型的铸造?使用注释?还有其他想法吗? ...
答案 0 :(得分: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));
}
答案 1 :(得分:0)
在撰写上述问题时,我遇到了以下解决方案。
解决仿制药和反思引起的问题...... 使用更多的反思!
鉴于上面定义的Operation
和OperationContainer
,请使用Class.getMethod(…)
和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);
}
}