,java,generics,generic-collections"/>

首页 > 解决方案 > Java 通用问题:无法转换 Map到 M 扩展地图

问题描述

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

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

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

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) -> ...);

标签: javagenericsgeneric-collections

解决方案


这似乎是对泛型的一个常见误解,即被调用者决定泛型参数的类型。事实上,调用者确实如此。

谁打电话来mapSupplier决定什么K,是什么。假设我正在调用它,我想成为,成为,成为。这是有效的,因为实现.UMKIntegerUStringMHashtable<Integer, String>HashtableMap

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;
}

编辑:

看到来电者,我认为您可以:

  • 也删除McollectToHashMapWithRandomMerge或者:
  • make collectToHashMapWithRandomMergeaccept a Supplier<M>,以便它的调用者可以决定地图的类型。

推荐阅读