gpt4 book ai didi

java - 可选 "ifPresent"通用通配符

转载 作者:行者123 更新时间:2023-12-04 03:42:04 24 4
gpt4 key购买 nike

我在OpenJDK(11)中发现Optional.ifPresent()的执行方法。 Here it is :

 public void ifPresent(Consumer<? super T> action) {
if (this.value != null) {
action.accept(this.value);
}
}

而且我不明白为什么要写这个特定的模板:<? super T>

例如,我们有 A、B、C 类:

private static class A {
protected void call() {
System.out.println("Call A");
}
}
private static class B extends A {
@Override
protected void call() {
System.out.println("Call B");
}
}
private static class C extends B {
@Override
protected void call() {
System.out.println("Call C");
}
}

有些人调用 main方法:

public static void main(String[] args) {
final Optional<B> opt = Optional.of(new B());
opt.ifPresent(A::call);
}

我可以用 opt.ifPresent(A::call); 调用我的主要方法和 opt.ifPresent(B::call);不能用 opt.ifPresent(C::call); .好的,我明白了。但为什么是<? super T> ?我可以使用 <T> 实现相同的行为模板。有人可以帮助我理解这一点并举例说明为什么这是必要的吗?

更新:

最后,我找到了一个例子,其中 <T> ifPresent(Consumer<? super T> action) 中的类型不够签名。

示例:假设我们方法的签名是:

 public void ifPresent(Consumer<T> action)

在这种情况下我们不能这样使用方法:

 Optional<B> opt = Optional.of(new B());
opt .ifPresent(new Consumer<Object>() {
@Override
public void accept(final Object obj) {
//compiler error: 'java: incompatible types'
}
});

但是在这种情况下:

public void ifPresent(Consumer<? super T> action)

这是可能的,代码编译没有任何错误。

最佳答案

covariance and contravariance的问题泛型类型。

函数类型的参数是逆变的。如果BA 的子类, 然后 Consumer<A>可以被认为是 Consumer<B> 的子类: 每当你需要 Consumer<B>你可以使用 Consumer<A> , 因为它接受 A作为参数,所以它也接受 B .

另一方面,函数的返回类型是协变的:a Supplier<B>有一个可以转换为 A 的返回值, 所以你可以认为它是 Supplier<A> 的子类.

不幸的是,这样的定义不适用于可变结构:如果你允许 List<B>成为 List<A> 的子类然后你可以写:

final List<B> listB = new ArrayList<>();
final List<A> listA = listB;
listA.add(new A()); // it is no longer a List<B>
final B b = listB.get(0); // ClassCastException

因此 Java 选择了不变泛型:Consumer<B>既不是 Consumer<A> 的子类也不是父类(super class).但我们要记住 Consumer<B> 事实上Consumer<A>的子类所以我们在函数的签名中使用边界。

当然可以这样写:

public <U super T> void ifPresent(Consumer<U super T> action) { ... }

(T参数指的是Optional<T>的类型参数),但是U从未在签名中使用。所以我们使用通配符 ? super T .

其他语言,如 Scala允许指定在类定义中以协变或逆变方式使用泛型类型是否安全。所以 Scala 会定义:

def ifPresent(Consumer[T] action): Unit { ... }

因为编译器已经知道,参数TConsumer是逆变的。

备注:如果你不写一个List , 你也可以通过 List<? extends A> 类型以协变的方式使用它.编译器不允许您调用 add(new A())在这样的物体上,因为 ?也可以是 A 的子类,在这种情况下调用会中断 List .但是调用get()肯定会返回可分配给 A 的东西.

关于java - 可选 "ifPresent"通用通配符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65849597/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com