asp*_*asp 6 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 { }
}
Run Code Online (Sandbox Code Playgroud)
编辑:Per @ Thielo的评论,引用superAction是des a to a Consumer<Pair<Animal, Animal>>a a Consumer<Object>.
给出test方法的正确类型是这样的:
void test(Consumer<? super Pair<? extends Animal, ? extends Animal>>)
Run Code Online (Sandbox Code Playgroud)
这种类型将允许我们传递一个Consumer<Object>to test,并且还允许我们使用诸如Pair<Dog, Dog>而不是仅仅的参数来调用消费者Pair<Animal, Animal>.
作为后续问题,与此更新类型的测试,它不会接受类似的方法参考void exactMatchAction<Pair<Animal, Animal>>了,只void exactMatchAction<Pair<? extends Animal, ? extends Animal>>.为什么是这样?
方法引用表达式(例如您的Variance::superAction)是多表达式(JLS8,15.13)。多表达式的类型可能会受到表达式的目标类型(JLS8,15.3)的影响,这是在该上下文(JLS8,5)中预期的类型,即,Consumer<Pair<Animal, Animal>>在您的情况下。
详细信息在 JLS8, 15.13.2 中有详细说明。基本思想是对函数接口类型(例如Consumer. 具体来说,方法类型只需要与函数类型一致Pair<Animal, Animal> -> void(注意,Consumer这里已经从类型考虑中消失了),这可以通过“identif[ying]与引用相对应的单个编译时声明”来满足(并具有void返回类型)。这里,“识别”声明的概念可以追溯到15.12.2,基本上描述了方法重载解析过程。换句话说,该语言现在采用Consumer<Pair<Animal, Animal>>.accept()(即Pair<Animal, Animal>) 所需的函数参数,并检查是否可以用该参数调用方法引用(这可以解决重载问题,以防存在多个同名静态方法)。
| 归档时间: |
|
| 查看次数: |
335 次 |
| 最近记录: |