捕获#1-of?超级 C 在通用接口中解释为 C

capture#1-of ? super C interpreted as C in generic interface

给出以下 类:

class A { public A a() {return new A();}; };
class B extends A { public B b() {return new B();} };
class C extends B { public C c() {return new C();} };
class D extends C { public D d() {return new D();} };

我想写一些 UnaryOperator 可以接受 A、B 和 C 的实例,但不能接受 D。

所以我选择声明引用类型是UnaryOperator<? super C>。由于我使用的是 super,这意味着它也可以接受 Object.

的实例
UnaryOperator<? super C> op1 = arg -> arg.a(); // does not compile, arg could be Object
UnaryOperator<? super C> op2 = arg -> arg.b(); // does not compile, arg could be Object
UnaryOperator<? super C> op3 = arg -> arg.c(); // does compile
UnaryOperator<? super C> op4 = arg -> arg.d(); // this is not expected to compile

为什么 op1 使代码无法编译并显示消息

Type mismatch: cannot convert from A to C

op2 使代码无法编译并显示消息

Type mismatch: cannot convert from B to C,

但是 op3 编译得很好,让我调用一个只在 C 中可用的方法?

Why does op1 makes the code fail to compile...?

当通用函数式接口被通配符参数化时,有不同的实例化可以满足通配符并产生不同的函数类型。例如,每个 1:

UnaryOperator<C> (function type C -> C);
UnaryOperator<B> (function type B -> B);
UnaryOperator<A> (function type A -> A);
UnaryOperator<Object> (function type Object -> Object);

是一个UnaryOperator<? super C>

有时,可以从上下文(例如 lambda 的参数类型)中获知函数类型。其他时候需要选一个:

UnaryOperator<? super C> op1 = (A arg) -> arg.a();
                                ^

UnaryOperator<? super C> op2 = (B arg) -> arg.b();
                                ^
...

如果您不选择一个,则使用边界 2:

UnaryOperator<? super C> op = arg -> arg.c(); // valid

其中 C 是一个边界,因此在这种情况下 lambda 表达式是 UnaryOperator<C>


1 - JLS 9.9. Function Types - the last paragraph.
2 - JLS 15.27.3. Type of a Lambda Expression - 如果T是通配符参数化的函数式接口类型并且lambda表达式是隐式类型的,那么地面目标类型是非通配符参数化 T.

@Oleksandr 已经告诉你编译失败的原因。我会告诉你为什么你不能使用UnaryOperator<? super C>只接受A, B, C而拒绝D


UnaryOperator<? super C> 并不意味着函数接受 ? super C。 这意味着 UnaryOperator<T> 中的通用 T? super C

假设您有一个实例 UnaryOperator<? super C> uo

  • uo.apply(new A())有意义吗?否,因为 UnaryOperator<B> 可分配给 UnaryOperator<? super C> 但不能接受 A.
  • uo.apply(new B())有意义吗?否,因为 UnaryOperator<C> 可分配给 UnaryOperator<? super C> 但不能接受 B.

那么uo能接受什么呢?答案是 C,因为只有 C 可以分配给任何 ? super C.

因此您的 UnaryOperator<? super C> 实际上与 UnaryOperator<C> 相同。尽管您的 IDE 可能会告诉您它接受 Object,但它不会接受无法分配给 C.

的对象