- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在努力理解变体在 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>>
.这是为什么?
最佳答案
方法引用表达式(例如您的 Variance::superAction
)是多边形表达式 (JLS8, 15.13)。多边形表达式的类型可能受表达式的目标类型 (JLS8, 15.3) 的影响,这是该上下文中预期的类型 (JLS8, 5),即 Consumer<Pair<Animal, Animal>>
,在你的情况下。
详细信息在 JLS8, 15.13.2 中有详细说明。基本思想是对功能接口(interface)类型进行特殊处理,例如 Consumer
.具体来说,方法类型只需要与函数类型一致(即 Pair<Animal, Animal> -> void
——注意 Consumer
已从此处的类型考虑中消失),这由“identif[ying ] 对应于引用的单个编译时声明”(并具有 void
作为返回类型)。在这里,“识别”声明的概念可以追溯到 15.12.2,基本上描述了方法重载解析过程。换句话说,该语言现在采用 Consumer<Pair<Animal, Animal>>.accept()
预期的函数参数。 (即 Pair<Animal, Animal>
)并检查是否可以用它调用方法引用(这解决了在有多个同名静态方法的情况下的重载)。
关于Java 类型变体,泛型类型的消费者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32429389/
我是一名优秀的程序员,十分优秀!