正确使用泛型与地图

时间:2013-05-13 21:47:31

标签: java generics

我有各种扩展baseItem的项目。 对于每种类型,我都有一个特殊的处理程序类。

我使用项目className使用处理程序的映射。 所以我的处理方法是这样的:

private boolean handle(BaseItem item) {

    BaseItemHandler bih = mapOfHandlers.get(item.getClass().getSimpleName());
    return bih.handleItem(item);

}

并且地图的类型为:

map<string,BaseItemHandler> mapOfHandlers;

但我(显然)收到了“未经检查的电话”警告。 什么是正确的做法

编辑:
这些项目是

public interface BaseItem{}

和BaseItemHandler是:

public interface BaseItemHandler<T extends BaseItem> {

    public boolean handleItem(T item);
}

2 个答案:

答案 0 :(得分:4)

java.util.Map不允许在单个键及其值之间表达类型约束,即使它确实如此,泛型也太弱而无法在Map.get()中使用该约束,因为执行Map.get()无法使编译器相信其参数的类型参数与正在访问的映射条目的类型参数相同。因此,任何此类实现都需要演员。

您可以使用经过检查的演员表:

abstract class Handler<I extends BaseItem> {
    final Class<I> iClass;
    protected Handler(Class<I> iClass) {
        this.iClass = iClass;
    }

    void handle(BaseItem i) {
        doHandle(iClass.cast(i));
    }

    abstract void doHandle(I i);
}

然而,这引入了一种具有过度宽松签名的方法,并且调用者可能会在程序的其他地方意外地使用该签名,从而不必要地绕过编译时类型检查。一个未经检查的演员似乎要付出较小的代价。

如果您担心堆污染的可能性,我会在注册时检查处理程序的类型:

class HandlerMap {
    Map<Class<?>, Handler<?>> map = new HashMap<>();

    public void register(Handler<?> h) {
        map.put(h.iClass, h);
    }

    public <I extends BaseItem> Handler<I> get(I i) {
        return (Handler<I>) map.get(i.getClass());
    }
}

答案 1 :(得分:1)

此方法不需要是通用的,请尝试此

private boolean handle(BaseItem item) {
    return mapOfHandlers.get(item.getClass().getSimpleName()).handleItem(item);
}