Java类型差异,泛型类型的消费者

时间:2015-09-06 23:47:11

标签: java contravariance

我很难理解Java中的方差是如何工作的。

在以下示例中,我定义了一个test函数Consumer。函数的定义没有逆变,所以我希望Consumer<Object>不是Consumer<Pair<Animal, Animal>>的子类型。然而,代码编译,测试接受lambda Variance:::superAction

我错过了什么?

import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;

import java.util.function.Consumer;

public class Variance {

  public static void main(String[] args) {
    test(Variance::exactMatchAction);
    test(Variance::superAction);
  }

  private static void exactMatchAction(Pair<Animal, Animal> pair) {
    System.out.println(pair.getLeft().getClass().getName());
  }

  private static void superAction(Object obj) {
    System.out.println(obj.getClass().getName());
  }

  private static void test(Consumer<Pair<Animal, Animal>> action) {
    action.accept(ImmutablePair.of(new Animal(), new Animal()));
    action.accept(ImmutablePair.of(new Dog(), new Dog()));
  }

  static class Animal {  }

  static class Dog extends Animal {  }
}

编辑:Per @ Thielo的评论,参考superActionConsumer<Pair<Animal, Animal>>而不是Consumer<Object>

提供test方法的正确类型如下:

void test(Consumer<? super Pair<? extends Animal, ? extends Animal>>)

此类型允许我们将Consumer<Object>传递给test,并且还允许我们使用Pair<Dog, Dog>之类的参数而不仅仅Pair<Animal, Animal>来调用消费者。

作为后续问题,使用此更新的测试类型,它将不再接受void exactMatchAction<Pair<Animal, Animal>>之类的方法引用,仅接受void exactMatchAction<Pair<? extends Animal, ? extends Animal>>。这是为什么?

1 个答案:

答案 0 :(得分:0)

方法引用表达式(例如Variance::superAction)是多重表达式(JLS8,15.13)。 poly表达式的类型可能受表达式目标类型(JLS8,15.3)的影响,这是该上下文中预期的类型(JLS8,5),即{{1在你的情况下。

细节在JLS8,15.13.2中详细说明。基本思想是对Consumer<Pair<Animal, Animal>>等功能接口类型进行特殊处理。具体来说,方法类型只需 congruent 到函数类型(Consumer - 注意Pair<Animal, Animal> -> void已经从类型考虑中消失了),这是由满足&#34;识别[ying]与参考&#34;相对应的单个编译时声明。 (并且Consumer作为返回类型)。在这里,&#34;识别&#34;的概念声明可以追溯到15.12.2,基本上描述了方法重载解析过程。换句话说,该语言现在采用void所期望的函数参数(即Consumer<Pair<Animal, Animal>>.accept())并检查是否可以使用该函数调用方法引用(如果存在多个静态方法,则解决了重载问题)同名)。

相关问题