【问题标题】:Type mismatch in nested contravariant type嵌套逆变类型中的类型不匹配
【发布时间】:2017-04-04 19:59:46
【问题描述】:

鉴于这样的课程(部分)

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 参数上不变时,即&lt;K, V&gt; Map&lt;K, V&gt; sorted(Map&lt;K, V&gt; map, Comparator&lt;Map.Entry&lt;K, V&gt;&gt; comparator) 它编译没有任何问题。但是,我认为我的代码没有违反任何类型关系。这是 Java 类型推断的问题吗?

我正在使用 OpenJDK 8。

【问题讨论】:

    标签: java generics type-inference contravariance


    【解决方案1】:

    泛型是不变的。如果您声明一个参数Comparater&lt;T&gt;,那么它期望的正是Comparator&lt;T&gt;。在这种情况下,您有KV 穿过地图,这使得K = StringV = Collection&lt;String&gt;。这将使第二个参数Comparator&lt;Entry&lt;? super String, ? super Collection&lt;String&gt;&gt;&gt;,并且您不能为其分配Comparator&lt;Entry&lt;String,Collection&lt;String&gt;&gt;&gt;,因为比较器的类型参数不完全匹配。

    您可以改为声明 Comparator 逆变器:

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

    【讨论】:

    • 嗯,我现在看到了问题。我同意KV 的推断类型(这就是我想要的),但我不明白这里的方差。看起来Comparator&lt;Map.Entry&lt;String, Collection&lt;String&gt;&gt;&gt; 确实不是Comparator&lt;Map.Entry&lt;? super String, ? super Collection&lt;String&gt;&gt;&gt; 的子类型,但为什么呢? StringString 的超类型,Collection&lt;String&gt;Collection&lt;String&gt; 也是如此。
    • 好吧,Map.Entry&lt;String, Collection&lt;String&gt;&gt; 肯定是Map.Entry&lt;? super String, ? super Collection&lt;String&gt;&gt; 的子类型,但是当您为每种类型构建Comparators 时,子类型关系就会中断,因为可以比较两个Map.Entry&lt;String,Collection&lt;String&gt;&gt; 对象的东西可以'不一定要比较两个任意的Map.Entry&lt;? super String, ? super Collection&lt;String&gt;&gt; 对象。
    • @DavidWallace,谢谢!现在我明白这一点了。那我会坚持&lt;K, V&gt; Map&lt;K, V&gt; sorted(Map&lt;K, V&gt; map, Comparator&lt;? super Map.Entry&lt;K, V&gt;&gt; comparator)。 :)
    猜你喜欢
    • 1970-01-01
    • 2016-10-21
    • 2011-08-11
    • 1970-01-01
    • 1970-01-01
    • 2021-04-30
    • 2019-08-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多