Reactor/WebFlux 的类型推断和类型变异问题

Problem of type inference and type variance for Reactor/WebFlux

假设有一个接口及其实现 class 为:

public interface InterfaceA {}

public class ClassA implements InterfaceA {

    public static Mono<ClassA> getMonoA() {
        return Mono.empty();
    }

}

然后,对于方法 Mono<InterfaceA> getMonoA(),以下实现会导致编译错误:

Mono<InterfaceA> getMonoA() {
    return ClassA.getMonoA();
}

不变类型 Mono<InterfaceA> 不是 Mono<ClassA> 的超 class 是有道理的,即使 InterfaceA 是 [=] 的超 class 18=],因此 ClassA.getMonoA() 的 return 类型 Mono<ClassA>Mono<InterfaceA>.

不匹配

但是,以下实现可以正常工作:

Mono<InterfaceA> getMonoA() {
    return Mono.just(new ClassA());
}

Mono.just方法实际上定义为public static <T> Mono<T> just(T data)。由于基因类型 T 在我的例子中是 ClassA,该方法应该 return Mono<ClassA> 的类型,这在我看来也应该引发编译错误。

我可以知道是否有一些机制让 Mono.just 方法 returns Mono<InterfaceA> 而不是 Mono<ClassA> 好吗?

我认为看待这个问题的一种方式是编译器如何解释类​​型 T。如果你定义

interface InterfaceB {
}

static class ClassB implements InterfaceB {
}

那么下面的代码将无法编译(如预期的那样)

    Mono<InterfaceA> getMonoTest() {
    return Mono.just(new ClassB());     
    }

与此类似的消息

type mismatch: cannot convert from Mono<ClassB> to Mono<InterfaceA>

所以编译器会检查类型T是否对应于方法的return类型。 MonoJustdefined 作为通用发布者,您 returning MonoJust<InterfaceA> 而不是 MonoJust<ClassA>.

final class MonoJust<T> extends Mono<T> ...

final T value;
MonoJust(T value) {
    this.value = Objects.requireNonNull(value, "value");
}

另一方面,MonoEmptydefined 作为 Publisher<Object>:

final class MonoEmpty extends Mono<Object> ....

static final Publisher<Object> INSTANCE = new MonoEmpty();

MonoEmpty() {
    // deliberately no op
}

并且您必须定义类型边界:

Mono<? extends InterfaceA> getMonoA() 

这就是 java 泛型的工作方式。在第二个示例中,java 编译器可以推断类型。这和定义

是一样的
Mono<InterfaceA> getMonoA() {
   return Mono.<InterfaceA>just(new ClassA());
}

但在第一个示例中,编译器无法自动将 Mono<ClassA> 转换为 Mono<InterfaceA>,但您可以通过应用映射函数来转换它

Mono<InterfaceA> getMonoA() {
     return ClassA.getMonoA1().map(Function.identity());
}

这与定义 .<InterfaceA>map(c -> c).map(c -> (InterfaceA) c) 相同。

或者您可以将方法定义为

public static <T extends InterfaceA> Mono<T> getMonoA() {
    return ClassA.getMonoA();
}

类似于 Mono.just 的定义。

由于 type erasureMono<InterfaceA>Mono<ClassA> 在运行时都将是 Mono,因此不会对元素类型进行真正的类型检查。您可以使用在这种情况下有效的不安全转换,但当您尝试访问对象时可能会导致 ClassCastException

Mono<InterfaceA> getMonoA() {
    return (Mono) ClassA.getMonoA();
}

这不是 Reactor 或 WebFlux 特有的东西。这同样适用于任何泛型类型。例如,List<InterfaceA>List<ClassA>.