- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在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的问题泛型类型。
函数类型的参数是逆变的。如果B
是 A
的子类, 然后 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 { ... }
因为编译器已经知道,参数T
在 Consumer
是逆变的。
备注:如果你不写一个List
, 你也可以通过 List<? extends A>
类型以协变的方式使用它.编译器不允许您调用 add(new A())
在这样的物体上,因为 ?
也可以是 A
的子类,在这种情况下调用会中断 List
.但是调用get()
肯定会返回可分配给 A
的东西.
关于java - 可选 "ifPresent"通用通配符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65849597/
我正在尝试用 Swift 编写这段 JavaScript 代码:k_combinations 到目前为止,我在 Swift 中有这个: import Foundation import Cocoa e
我是一名优秀的程序员,十分优秀!