嵌套逆变类型中的类型不匹配

时间:2017-04-04 19:59:47

标签: java generics type-inference contravariance

鉴于此类(部分内容)

import java.util.*;
import java.util.stream.Collectors;

public class A {
    private Map<String, Set<String>> map = new LinkedHashMap<>();

    public Map<String, Collection<String>> getMap() {
        return Collections.unmodifiableMap(map);
    }

    public static <K, V> Map<K, V> sorted(Map<K, V> map, Comparator<Map.Entry<? super K, ? super V>> comparator) {
        return map
                .entrySet()
                .stream()
                .sorted(comparator)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    public Map<String, Collection<String>> getSortedMap() {
        Comparator<Map.Entry<String, Collection<String>>> cmp =
                Map.Entry.comparingByValue(Comparator.comparingInt(Collection::size));
        return sorted(getMap(), cmp);
    }
}

我在编译时遇到错误

error: method sorted in class A cannot be applied to given types;
    return sorted(getMap(), cmp);
            ^
            required: Map<K,V>,Comparator<Entry<? super K,? super V>>
        found: Map<String,Collection<String>>,Comparator<Entry<String,Collection<String>>>
        reason: cannot infer type-variable(s) K,V
        (argument mismatch; Comparator<Entry<String,Collection<String>>> cannot be converted to Comparator<Entry<? super K,? super V>>)
        where K,V are type-variables:
        K extends Object declared in method <K,V>sorted(Map<K,V>,Comparator<Entry<? super K,? super V>>)
        V extends Object declared in method <K,V>sorted(Map<K,V>,Comparator<Entry<? super K,? super V>>)
        1 error

当我将A.sorted签名更改为comparator参数(即<K, V> Map<K, V> sorted(Map<K, V> map, Comparator<Map.Entry<K, V>> comparator)}不变时,它会毫无问题地进行编译。但是,我不认为我的代码违反了任何打字关系。这是Java类型推断的问题吗?

我正在使用OpenJDK 8。

1 个答案:

答案 0 :(得分:2)

泛型是不变的。如果您声明参数Comparater<T>,那么它完全符合Comparator<T>。在这种情况下,您可以通过地图KV生成K = StringV = Collection<String>。这将产生第二个参数Comparator<Entry<? super String, ? super Collection<String>>>,并且您不能为此分配Comparator<Entry<String,Collection<String>>>,因为比较器的类型参数不会完全匹配。

您可以改为声明Comparator反变量:

public static <K, V> Map<K, V> sorted(Map<K, V> map,
        Comparator<? super Map.Entry<K, V>> comparator) {
    ...
}