有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

为什么泛型超类型的Java类型推断在此中断?

给出以下Java代码:

import java.util.AbstractMap.SimpleEntry;
import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;
import java.util.Optional;

public class Test {
    public static void main(String[] args) {
        SimpleEntry<Integer, String> simpleEntry = new SimpleEntry<>(1, "1");
        Optional<Entry<Integer, String>> optionalEntry = Optional.of(simpleEntry);
        Optional<SimpleEntry<Integer, String>> optionalSimpleEntry = Optional.of(simpleEntry);

        List<Entry<Integer, String>> list1 = Arrays.asList(simpleEntry);
        List<Optional<Entry<Integer, String>>> list2 = Arrays.asList(optionalEntry);
        List<Optional<SimpleEntry<Integer, String>>> list3 = Arrays.asList(optionalSimpleEntry);
        List<Optional<Entry<Integer, String>>> list4 = Arrays.asList(optionalSimpleEntry);
    }
}

初始化listlist2list3的表达式工作正常。但是,在Eclipse中初始化list4的表达式因以下错误而中断:

Type mismatch: cannot convert from List<Optional<AbstractMap.SimpleEntry<Integer,String>>>
to List<Optional<Map.Entry<Integer,String>>>

javac中的这个错误:

Test.java:16: error: incompatible types: inference variable T has incompatible bounds
        List<Optional<Entry<Integer, String>>> list4 = Arrays.asList(optionalSimpleEntry);
                                                                    ^
    equality constraints: Optional<Entry<Integer,String>>
    lower bounds: Optional<SimpleEntry<Integer,String>>
  where T is a type-variable:
    T extends Object declared in method <T>asList(T...)

但是AbstractMap.SimpleEntry直接实现了Map.Entry。那么,当类型推断适用于list1list3时,为什么类型推断会中断list4(就这一点而言,也适用于optionalEntry的赋值)

特别是,我不明白为什么对list1的赋值有效,而对list4的赋值无效


共 (2) 个答案

  1. # 1 楼答案

    因此,让我们显式地编写我们期望推断的类型。此外,我们将把声明放在用法附近

    SimpleEntry<Integer, String> simpleEntry = ...
    List<Entry<Integer, String>> list1 =
        Arrays.<Entry<Integer, String>>asList(simpleEntry);
    

    SimpleEntry<xyz>是一个Entry<xyz>,所以这很好

    Optional<Entry<Integer, String>> optionalEntry = ...
    List<Optional<Entry<Integer, String>>> list2 =
        Arrays.<Optional<Entry<Integer, String>>>asList(optionalEntry);
    

    Optional<xyz>是一个微不足道的Optional<xyz>

    Optional<SimpleEntry<Integer, String>> optionalSimpleEntry = ...
    List<Optional<SimpleEntry<Integer, String>>> list3 =
        Arrays.<Optional<SimpleEntry<Integer, String>>>asList(optionalSimpleEntry);
    

    Optional<xyz>又是一个微不足道的Optional<xyz>

    Optional<SimpleEntry<Integer, String>> optionalSimpleEntry = ...
    List<Optional<Entry<Integer, String>>> list4 =
        Arrays.<Optional<Entry<Integer, String>>>asList(optionalSimpleEntry);
    

    Optional<SimpleEntry<xyz>>不是一个Optional<Entry<xyz>>

    您可以使用Optional<? extends Entry<xyz>>

  2. # 2 楼答案

    我假设您理解为什么不能将Optional<SimpleEntry<Integer,String>>分配给类型为List<Optional<Entry<Integer, String>>>的变量。如果没有,请阅读问题和建议;A Is List a subclass of List? Why are Java generics not implicitly polymorphic?

    但是,您的问题是为什么list1声明有效,而list4声明无效

    list1list4声明之间存在差异。对于list1,表格为:

    SimpleEntry<Integer, String> simpleEntry = ...;
    List<Entry<Integer, String>> list = Arrays.asList<T>(simpleEntry);
    

    在这种情况下,Arrays.asList方法的类型变量T尚未固定为特定类型。它的上限为SimpleEntry<Integer, String>(类型为simpleEntry

    根据Java Language Specification, section 18.5.2, "Invocation Type Inference",编译器将通过将asListList<T>)的返回类型约束为调用上下文目标类型(List<Entry<Integer, String>>),进一步约束类型T

    这是可能的;当编译器选择T为Entry<Integer, String>时,整个表达式都适合,因为SimpleEntry<Integer, String>类型的值可以分配给Entry<Integer, String>类型的变量

    对于list4,表格为:

    SimpleEntry<Integer, String> simpleEntry = new SimpleEntry<>(1, "1");
    Optional<SimpleEntry<Integer, String>> optionalSimpleEntry = Optional.of(simpleEntry);
    List<Optional<Entry<Integer, String>>> list4 = Arrays.asList<T>(optionalSimpleEntry);
    

    这里,T最初被限制为Optional<SimpleEntry<Integer, String>>的上限。表达式上下文的目标类型是List<Optional<Entry<Integer, String>>>。编译器不可能找到一个既适合两者的T

    无法将类型为Optional<SimpleEntry<Integer, String>>的值分配给类型为Optional<Entry<Integer, String>>>的变量

    这就是编译器抱怨的原因

    简单地说

    更简单地说,对于泛型类型不受约束且存在约束泛型类型的表达式上下文的方法,它适用于一个层次的参数化

    你可以说

    Dog dog = ...;
    List<Animal> animals = Arrays.asList(dog);
    

    但在更深层次的参数化中,它不起作用

    Optional<Dog> optionalDog = ...;
    List<Optional<Animal>> optionalAnimals = Arrays.asList(optionalDog);