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

发布于 2025-01-15 18:15:16 字数 1239 浏览 2 评论 0原文

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

public interface InterfaceA {}

public class ClassA implements InterfaceA {

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

}

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

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

不变类型 Mono 不是 Mono 的超类是有道理的> 即使 InterfaceAClassA 的超类,因此 ClassA.getMonoA() 的返回类型是MonoMono 不匹配。

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

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

Mono.just 方法实际上定义为 public static;单声道只是(T数据)。由于我的例子中的通用类型 TClassA,该方法应该返回 Mono 的类型,这也应该引发编译错误在我心里。

我想知道是否有一些机制让 Mono.just 方法返回 Mono 而不是 Mono

Let's say there is an interface and its implement class as:

public interface InterfaceA {}

public class ClassA implements InterfaceA {

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

}

And then, for the method Mono<InterfaceA> getMonoA(), the following implementation causes a compile error:

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

It makes sense that the invariance type Mono<InterfaceA> is not the super class of Mono<ClassA> even if InterfaceA is the super class of ClassA and therefore the return type of ClassA.getMonoA() which is Mono<ClassA> does not match the Mono<InterfaceA>.

However, the following implementation works properly:

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

The Mono.just method is acturally defined as public static <T> Mono<T> just(T data). As the geneic type T in my case is ClassA, the method should return the type of Mono<ClassA> which should also raise a compile error in my mind.

May I know if there are some mechanisms let Mono.just method returns Mono<InterfaceA> instead of Mono<ClassA> please?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

苏辞 2025-01-22 18:15:16

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

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

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

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

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

或者您可以将您的方法定义为

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

类似于 Mono.just 的定义方式。

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

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

这不是 Reactor 或 WebFlux 特有的东西。这对于任何泛型类型都有效。例如,ListList

This is the way how java generics works. In the second example java compiler could infer type. This is the same as defining

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

But in the first example compiler could not cast Mono<ClassA> to Mono<InterfaceA> automatically but you could cast it by apply a map function

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

that is the same as defining .<InterfaceA>map(c -> c) or .map(c -> (InterfaceA) c).

or you could define your method as

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

similar how Mono.just is defined.

Due to type erasure, both Mono<InterfaceA> and Mono<ClassA> will be Mono during runtime, so there will be no real type check regarding the element type. You could use unsafe cast that will work in this case but potentially could result in ClassCastException when you try to access the object

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

It's not something specific to Reactor or WebFlux. The same is valid for any generic types. For example, List<InterfaceA> vs List<ClassA>.

不甘平庸 2025-01-22 18:15:16

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

interface InterfaceB {
}

static class ClassB implements InterfaceB {
}

,则以下内容将不会编译(如预期),

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

并显示类似于此的消息

类型不匹配:无法从 Mono转换;到 Mono

因此编译器会检查类型 T 是否对应于方法的返回类型。 MonoJust已定义作为通用发布者,您返回的是 MonoJust 而不是 MonoJust

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

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

另一方面,MonoEmpty定义Publisher

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

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

MonoEmpty() {
    // deliberately no op
}

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

Mono<? extends InterfaceA> getMonoA() 

I think one way to look at this is the question how the type T is interpreted by the compiler. If you define

interface InterfaceB {
}

static class ClassB implements InterfaceB {
}

then the following will not compile (as expected)

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

with the message similar to this one

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

So the compiler does check if the type T corresponds to the return type of the method. MonoJust is defined as a generic Publisher and you are returning MonoJust<InterfaceA> not MonoJust<ClassA>.

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

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

On the other hand, MonoEmptyis defined as a Publisher<Object>:

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

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

MonoEmpty() {
    // deliberately no op
}

and you would have to define type boundaries:

Mono<? extends InterfaceA> getMonoA() 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文