Java 泛型:"T2 extends T1" 是否意味着 "T1 super T2"?

Java generics: Does "T2 extends T1" imply "T1 super T2"?

如果我有一个泛型 <T2 extends T1>,编译器会推断出 T1 super T2 吗?

我有一个更复杂的集合,我将其简化为下面的 MWE。该集合应可与具有任何子类型元素的任何此类集合合并。

现在我想知道,为什么在merge中对forEach的调用不被接受。它失败了

java.util.function.Consumer<java.util.Optional> cannot be converted to java.util.function.Consumer<java.util.Optional<? super T2>>

我已经在下图中描述了类型关系。在 merge 中,T2 扩展了 T1。对 forEach 的调用应用于 other 对象,因此 thisT1 成为 other.forEach? 和 [=20 this.merge 的 =] 是 otherT1。因此,this' T1 应该被接受为 otherT1.

的超级

我也试过 public void merge(Group<? extends T> other) 结果相同。并且 public void merge(Group<T> other) 不接受包含 T1.

任何子类型元素的此类集合

MWE:

class Group<T1> {
    public <T2 extends T1> void merge(Group<T2> other) {
        Consumer<Optional<T1>> task = t -> t.ifPresentOrElse(this::foo, this::bar);
        other.forEach(task);
    }

    public Collection<Optional<T1>> values() {
        return List.of();
    }

    public void forEach(Consumer<Optional<? super T1>> consumer) {
        values().forEach(consumer);
    }

    private void foo(T1 t) {}

    private void bar() {}
}

关系:

   this.T1      -becomes->  other.forEach.?
      ^                            |
      |                          super
   extends                         |
      |                            v
this.merge.T2     -is->        other.T1

如果你有一个 Consumer<Optional<? super T1>> consumer 那么你可以将它传递给(给 accept(T) 方法)一个 Optional<Object> 因为 ObjectT1 的超类型.

另一方面,您不能将 Optional<Object> 传递给 Consumer<Optional<T1>> task,因为 T1 可能不是 Object

因此您不能将 Consumer<Optional<T1>> task 分配给 Consumer<Optional<? super T1>> consumer 以防止您的消费者传递它不期望的类型的对象。

您可以使用

解决您的问题
class Group<T1> {
    public <T2 extends T1> void merge(Group<T2> other) {
        Consumer<Optional<? extends T1>> task=t->t.ifPresentOrElse(this::foo, this::bar);
        other.forEach(task);
    }

    public Collection<Optional<T1>> values() {
        return List.of();
    }

    public void forEach(Consumer<? super Optional<T1>> consumer) {
        values().forEach(consumer);
    }

    private void foo(T1 t) {}

    private void bar() {}
}

这是 PECS rule 的应用程序。

您的 task 会将 Optional 视为 生产者 ,因此,必须声明 Optional<? extends T1> 以允许可选生产子类型T1 个。我们知道optional会一直充当生产者,但是Java的泛型类型系统没有类总是充当生产者或消费者的概念,这里需要显式的? extends T1 .

forEach 接收到一个消费者,即使是在接口名称中的字面上,所以 ? super … 是声明此消费者可能是 Optional<T1> 超类型的消费者的正确方法。这不仅包括 ObjectOptional 的超类,还包括 Optional<? extends T1>T1 := T2,如 merge 中的调用,如 Optional<? extends T1> ] 是 Optional<T2>.

的超类型

当然你也可以直接使用

解决问题
Consumer<Optional<T2>> task = t -> t.ifPresentOrElse(this::foo, this::bar);

因为这只需要 foo 接受一个 T2 参数,它总是这样做,因为 T2T1 的子类型。但是更改 forEach 的签名以提高灵活性始终是一个很好的举措。由于它是一个 public 方法,因此可能会有其他调用者从中受益。