是否可以将两个通配符类型声明为相同类型?

时间:2011-12-06 23:13:44

标签: java generics

我想创建一个从(a)类类型到(b)long(已定义类类型的对象的标识符)到(c)对象本身的映射。

我有以下内容:

 protected HashMap<Class<?>, HashMap<Long, ?>> obj = new HashMap<Class<?>, HashMap<Long, ?>>();

是否有可能以某种方式表示第一个?必须与第二个?的类型相同?我希望这样的事情,但这是不可能的:

protected <T> HashMap<Class<T>, HashMap<Long, T>> obj = new HashMap<Class<T>, HashMap<Long, T>>();

4 个答案:

答案 0 :(得分:5)

作为替代方案,您可以使用少量非类型安全的代码封装,以强制执行约束:

class Cache {
    private Map<Class<?>, Map<Long, ?>> items = new HashMap<Class<?>, Map<Long, ?>>();

    private <T> Map<Long, T> getItems(Class<T> type) {
        @SuppressWarnings("unchecked")
        Map<Long, T> result = (Map<Long, T>) items.get(type);
        if (result == null) {
            result = new HashMap<Long, T>();
            items.put(type, result);
        }
        return (Map<Long, T>) result;
    }

    public <T> void addItem(Class<T> type, Long id, T item) {
        getItems(type).put(id, item);
    }

    public <T> T getItem(Class<T> type, Long id) {
        return type.cast(getItems(type).get(id));
    }
}

type.cast()中的getItem()对于编译器不必抱怨是必要的,但它有助于捕获错误类型的对象提前进入缓存。

答案 1 :(得分:2)

通配符的每个出现对应于不同的类型,表示该类型的类型参数的唯一适当范围是外部HashMap中的条目。遗憾的是,HashMap不允许在其类型参数中约束条目类型,如:

class Entry<K,V> {
    // fields omitted
}

class Map<E extends Entry<?,?> {

}

class EntityCacheEntry<E> extends Entry<Class<E>, Map<Entry<Long, E>>> { }

class EntityCache extends Map<EntityCacheEntry<?>> { }

即使它确实如此,也没有办法在不使用未经检查的强制转换的情况下实现Map.get,因为我们必须将其类型参数约束为E所代表的类型系列的特定成员 - 并且您不能在Java中约束类型参数的类型参数。

因此,您唯一的办法是编写一个外观,其api强制执行类型不变量,但内部使用强制转换:

class EntityCache {
    Map<Class<?>, Map<Long, Object>> map = new HashMap<>();

    public <E> void put(Class<E> clazz, long id, E entity) {
        map.get(clazz).put(id, entity);
        // TODO create map if it doesn't exist yet
    }

    public <E> E get(Class<E> clazz, long id) {
        return clazz.cast(map.get(clazz).get(id));
        // TODO what if not found?
    }
}

答案 2 :(得分:0)

您可以使用特定的泛型定义扩展HashMap类,并创建一个以<T>为参数的泛型类,如下所示:

public class MyHashMap<T> extends HashMap<Class<T>, HashMap<Long, T>> { ...

答案 3 :(得分:0)

您可能想要的是:HashMap<Class<?>, HashMap<Long, Object>>。因为您将在其中放置不同类型的对象,Object是允许您添加任何类型对象的类型参数。

不要与通配符(?)混淆。它具有相反的含义 - 它意味着参数是某种类型(因此所有对象必须是该类型)但我们不知道它是什么,因此我们根本不能放任何东西。那不是你想要的。