如何在Map中使用具有不同类型值的泛型

时间:2018-01-08 17:48:15

标签: java generics

我有一个通用的<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="Hotspot"></div> <div class="Hotspot"></div> <div class="Hotspot"></div>界面:

Command

以及一些实施:

public interface Command<T> {
    public void execute(T value);
}

我需要的是public class ChangeName implements Command<String>{ public void execute(String value) {...} } public class SetTimeout implements Command<Integer>{ public void execute(Integer value) {...} } 来将命令名与特定的Map对象相关联:

Command

显然,我在声明Map<String, Command> commands = new HashMap<>(); ... commands.put("changeName", new ChangeName()); 时收到rawtypes警告。 如果我使用问号,我最终会遇到编译错误:

Map
  

类型Command中的execute(capture#2-of?)方法不适用于参数(String)

我知道你不能拥有一个不可重复类型的类型安全异构容器( Effective Java 中的第29项),但解决这个问题的最佳方法是什么问题

2 个答案:

答案 0 :(得分:1)

如果您从逻辑上考虑它,那么您的所有命令模板必须满足的最高通用接口是什么?

看看你的String,Integer的例子,看起来它不能只是Java Object。试试这个,

var swipeRight = new UISwipeGestureRecognizer((s) => { swiped(s); });

private void swiped(UISwipeGestureRecognizer s) {
     Console.WriteLine("User swiped right");  
}

修改: 基本上,您在声明时添加模板信息,但在使用时会想要完全删除它。这里有两个选择:

a)您不使用泛型,因为您无法将它们用于潜力。处理简单的Object类,而不是在特定的执行函数中,只测试正确的类型。

b)为不同类型创建不同的地图。通过这种方式,您可以将模板用于其潜力。

答案 1 :(得分:1)

我认为你需要让命令在运行时知道它们可接受的参数:

export CUDA_HOME='/usr/local/cuda'
export LD_LIBRARY_PATH='/usr/local/cuda/lib64'

# Override PATH
export PATH=${CUDA_HOME}/bin:${PATH}

现在使用代码将是这样的:

public abstract class Command<T> {
    private final Class<T> argumentClass;

    protected Command(Class<T> argumentClass) {
        this.argumentClass = argumentClass;
    }

    public abstract <U extends T> void execute(U argument);


    @SuppressWarnings("unchecked")
    public final <U> Command<? super U> cast(Class<U> argumentClass) {
        if (this.argumentClass.isAssignableFrom(argumentClass)) {
           return (Command<? super U>) this;
        } else {
           throw new UnsupportedOperationException("this command cannot handle argument of type " + argumentClass.getName());
        }
    }
}

上面的抑制警告是令人讨厌的,因为演员必须始终为真,但是private <U> void executeCommand(final String name, final U arg) { @SuppressWarnings("unchecked") Class<U> clazz = (Class<U>) arg.getClass(); commands.get(name).cast(clazz).execute(arg); } 的最终定义限制为返回getClass

地图可以输入为:

Class<?>

每个命令子类都将扩展抽象Map<String, Command<?>> commands = new HashMap<>();类。

例如匿名内部类定义o stderr的打印字符串命令:

Command

独立版本:

final Command<String> printString = new Command<String>(String.class) {
    public <U extends String> void execute(U arg) {
        System.err.println(arg);
    }
};

如果您愿意,可以提取public StdErrPrintCommand extends Command<String> { public StdErrPrintCommand() { super(String.class); } @Override public <U extends String> void excecute(U arg) { System.err.println(arg); } } 接口并将抽象类重命名为Command