Java 通用问题 : cannot cast Map<K, V> 到 M extends Map<K, V>

标签 java generics generic-collections

在尝试编写一些通用代码时,我遇到了一个问题。当然,我找到了一些解决方法,但为什么下面的代码仍然不起作用?

private static <K, U, M extends Map<K, U>>
Supplier<M> mapSupplier() {
    return  HashMap::new;
}

返回

Error:(25, 17) java: incompatible types: bad return type in lambda expression
    no instance(s) of type variable(s) K,V exist so that java.util.HashMap<K,V> conforms to M

更新: 我需要这个 map 供应商来创建自定义 map 收集器:

public static <E, K, V, M extends Map<K, V>>
Collector<E, ?, M> collectToHashMapWithRandomMerge(BiConsumer<M, E> accumulator) {
    return Collector.of(mapSupplier(),
            accumulator,
            TjiCollectionUtils.randomMapMerger());
}

HashMap::new调用Collector.of也会导致同样的编译错误

理想情况下,我不想创建额外的方法参数而只使用以下内容:

  public static <E, K, V, M extends Map<K, V>>
Collector<E, ?, M> collectToHashMapWithRandomMerge(BiConsumer<M, E> accumulator) {
    return Collector.of(HashMap::new,
            accumulator,
            TjiCollectionUtils.randomMapMerger());
}

回答 我最终做出了:

public static <E, K, V>
Collector<E, ?, Map<K, V>> collectToMapWithRandomMerge(BiConsumer<Map<K, V>, E> accumulator) {
    return Collector.of(HashMap::new,
            accumulator,
            TjiCollectionUtils.randomMapMerger());
}

调用方式如下:

MyCollectionUtils.collectToMapWithRandomMerge(
    (Map<String,Integer> m, SomeClassToExtractFrom e) -> ...);

最佳答案

这似乎是对泛型的一个普遍误解,即由被调用者决定泛型参数是什么类型。事实上,来电者确实如此。

谁调用mapSupplier决定什么K , UM是。假设我正在调用它,我想要 K成为Integer , U成为String , 和 M成为Hashtable<Integer, String> .这是有效的,因为 Hashtable工具 Map .

Supplier<Hashtable<Integer, String>> htSupplier = mapSupplier();
Hashtable<Integer, String> ht = htSupplier.get();

作为调用者,我希望上面的方法有效,但是 htSupplier.get ,通过你的实现,实际上会给我一个 HashMap<Integer, String> ,这是与 Hashtable 无关的类型(就继承层次而言)。

换句话说,mapSupplier单枪匹马决定M应该是 HashMap<K, U>同时还说它适用于任何 M实现 Map<K, U> .

每当您看到自己编写一个决定其通用参数是什么的“通用”方法时,该方法可能不应该具有该通用参数。因此,mapSupplier应该在没有 M 的情况下重写参数:

private static <K, U>
Supplier<HashMap<K, U>> mapSupplier() {
    return  HashMap::new;
}

编辑:

看到调用者,我想你可以:

  • 删除M来自 collectToHashMapWithRandomMerge以及,或者:
  • 制作collectToHashMapWithRandomMerge接受 Supplier<M> ,以便它的调用者可以决定 map 的类型。

关于Java 通用问题 : cannot cast Map<K, V> 到 M extends Map<K, V>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60263977/

相关文章:

java - java中如何根据子字符串的长度将字符串转换为子字符串数组?

java - 建议…JavaServer Faces(JSF),Struts,model2和其他

generics - 为什么 impl 不在范围内

typescript - 如何在 TypeScript 中为特定类型的泛型类型创建扩展方法

swift - 通用CollectionView快速

java - setOnPageChangeListener 不调用 onPageSelected

java - Android - 基于facebook的Firebase登录和调用Facebook Graph Api问题

ios - Swift:通过闭包参数解决函数重载问题?

c# - 限制通用集合的大小?

c# - 按数据库中的原始数据分组