Java 一般问题:无法将 Map<K,V> 转换为 M extends Map<K, V>
Java Generic issue: cannot cast Map<K,V> to M extends Map<K, V>
在尝试编写一些通用代码时遇到了问题。当然,我找到了一些解决方法,但为什么下面的代码不起作用?
private static <K, U, M extends Map<K, U>>
Supplier<M> mapSupplier() {
return HashMap::new;
}
这个returns
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) -> ...);
M extends Map<K, V>
表示扩展 Map
的 特定 class。 HashMap
是扩展 Map
的 class,但是 M
可以是 LinkedHashMap
; HashMap
不是 LinkedHashMap
.
你似乎已经得到一个 Supplier<M>
作为参数:
public static <E, K, V, M extends Map<K, V>>
Collector<E, ?, M> collectToHashMapWithRandomMerge(Supplier<M> mapSupplier /* HERE */, BiConsumer<M, E> accumulator) {
return Collector.of(mapSupplier(),
accumulator,
TjiCollectionUtils.randomMapMerger());
}
因此,只需使用 mapSupplier
(参数)而不是 mapSupplier()
(调用方法的结果)。
这似乎是对泛型的一个普遍误解,即由被调用者决定泛型参数是什么类型。事实上,来电者确实如此。
谁调用 mapSupplier
就可以决定 K
、U
和 M
是什么。假设我正在调用它,我希望 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>
,同时还说它将适用于任何实现 Map<K, U>
.
每当您看到自己编写一个 "generic" 方法来决定其通用参数是什么时,该方法可能不应该具有该通用参数。因此, mapSupplier
应该可以在没有 M
参数的情况下重写:
private static <K, U>
Supplier<HashMap<K, U>> mapSupplier() {
return HashMap::new;
}
编辑:
看到来电者,我想你可以:
- 同时从
collectToHashMapWithRandomMerge
中删除 M
,或者:
- 让
collectToHashMapWithRandomMerge
接受一个Supplier<M>
,这样它的调用者可以决定地图的类型。
在尝试编写一些通用代码时遇到了问题。当然,我找到了一些解决方法,但为什么下面的代码不起作用?
private static <K, U, M extends Map<K, U>>
Supplier<M> mapSupplier() {
return HashMap::new;
}
这个returns
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) -> ...);
M extends Map<K, V>
表示扩展 Map
的 特定 class。 HashMap
是扩展 Map
的 class,但是 M
可以是 LinkedHashMap
; HashMap
不是 LinkedHashMap
.
你似乎已经得到一个 Supplier<M>
作为参数:
public static <E, K, V, M extends Map<K, V>>
Collector<E, ?, M> collectToHashMapWithRandomMerge(Supplier<M> mapSupplier /* HERE */, BiConsumer<M, E> accumulator) {
return Collector.of(mapSupplier(),
accumulator,
TjiCollectionUtils.randomMapMerger());
}
因此,只需使用 mapSupplier
(参数)而不是 mapSupplier()
(调用方法的结果)。
这似乎是对泛型的一个普遍误解,即由被调用者决定泛型参数是什么类型。事实上,来电者确实如此。
谁调用 mapSupplier
就可以决定 K
、U
和 M
是什么。假设我正在调用它,我希望 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>
,同时还说它将适用于任何实现 Map<K, U>
.
每当您看到自己编写一个 "generic" 方法来决定其通用参数是什么时,该方法可能不应该具有该通用参数。因此, mapSupplier
应该可以在没有 M
参数的情况下重写:
private static <K, U>
Supplier<HashMap<K, U>> mapSupplier() {
return HashMap::new;
}
编辑:
看到来电者,我想你可以:
- 同时从
collectToHashMapWithRandomMerge
中删除M
,或者: - 让
collectToHashMapWithRandomMerge
接受一个Supplier<M>
,这样它的调用者可以决定地图的类型。