我很努力地理解Java中的差异是如何工作的。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 { }
}
编辑:每@ Thielo的评论,参考superAction
被脱到Consumer<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>>
。为什么是这样?
据我所知,没有警告。 – asp
不知道这是如何实现的,但它确实有道理。对象的消费者也可以消费对。如果你改变这个参数来表示一个字符串,你会得到一个错误,对吗? – Thilo
真的,我不知道。但我的猜测是这与'@ FunctionalInterface'的处理方式有关。它可能不关心接口本身的类型参数,只是它们在方法中被引用的方式。所以'Object - > void'方法可以用作'Pair <> - > void',因为如果它可以消耗*任何对象*,那么当然可以消耗一对。 – ryachza