使用具有 L 值和 R 值的无界泛型调用函数

Fea*_*rUs 7 java generics types type-inference compiler-errors

我不完全理解为什么以下代码不起作用:

package org.example;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {

    public interface MyInt<E> {
    }

    public static final class MyNum<E> implements MyInt<E> {
        private E privados;
    }

    public static void f(List<? extends MyInt> l) {
        System.out.println("from List<?>");
    }

    public static void main(String[] args) {
        var m = new MyNum();
        List<MyNum> l = Arrays.asList(m);

        ArrayList<MyInt> r = l.stream().collect(Collectors.toCollection(ArrayList<MyInt>::new));
        f(r);
        f(l.stream().collect(Collectors.toCollection(ArrayList<MyInt>::new)));
    }
}
Run Code Online (Sandbox Code Playgroud)

电话f(r)有效,但下一行中对右值版本的调用无效。

很明显,当我们有程序员强制执行的特定要求时,编译器中发生的约束求解过程很高兴,但是当我们要求它通过直接将ArrayList<MyInt>结果传递给 来进行端到端约束求解时,编译器将发送这样的错误:collectf

java: incompatible types: inferred type does not conform to upper bound(s)
    inferred: java.lang.Object&java.util.List<? extends org.example.Main.MyInt>&java.util.Collection<org.example.Main.MyNum>
    upper bound(s): java.util.Collection<org.example.Main.MyNum>,java.util.List<? extends org.example.Main.MyInt>,java.lang.Object
Run Code Online (Sandbox Code Playgroud)

推断与上限之间的唯一区别(来自错误消息):

  1. 使用&vs,
  2. 对象的顺序(相反)

我假设顺序不重要(它们是设置的)并且&,特殊含义。

有人对正在发生的事情有更彻底、更少“挥手”的解释吗?

小智 1

这种推理不一致是由于 lambda 表达式造成的。您可以在OpenJDK.com 上的这封邮件中获得解释(主题:JDK-8219318 (???):收集到 HashMap 时推断的类型不符合上限)

也许新的Java编译器(javac)已经解决了这个问题。

如果添加显式类型,这个问题就可以解决。例子:

f((ArrayList<? extends MyInt>) l.stream().collect(Collectors.toCollection(ArrayList<MyInt>::new)));

f((ArrayList<MyInt>) l.stream().collect(Collectors.toCollection(ArrayList<MyInt>::new)));

f((List<? extends MyInt>) l.stream().collect(Collectors.toCollection(ArrayList<MyInt>::new)));

f((List<MyInt>) l.stream().collect(Collectors.toCollection(ArrayList<MyInt>::new)));
Run Code Online (Sandbox Code Playgroud)

此外,您还可以提供供应商的实现。在这种情况下,您不需要添加显式类型。匿名类的例子:

f(l.stream().collect(Collectors.toCollection(new Supplier<List<MyInt>>(){
   @Override
   public List<MyInt> get() {
   return new ArrayList<MyInt>();
  }
})));
Run Code Online (Sandbox Code Playgroud)