我已经编写了以下构建器(简化版本):

public static final class Builder<T extends SigEvents> {
    private Class<T> sigEventsType;
    private BiFunction<T, MessageExtractor, SigEventsEmitter<T>> emitterMapper;

    public Builder<T> forEmitter(@Nonnull Class<T> emitterType, @Nonnull BiFunction<T, MessageExtractor, SigEventsEmitter<T>> emitterMapper) {
        this.sigEventsType = emitterType;
        this.emitterMapper = emitterMapper;
        return this;
    }

    public SigEventsEmitter<T> buildEmitter() {
        //do some stuff which end up setting sigEventLogger and sink
        return emitterMapper.apply(sigEventLogger, sink);
    }

}

现在,我try 使用它来初始化一个JSFSigEventsEmitter的实例,该实例声明如下:

public final class JSFSigEventsEmitter extends SigEventsEmitter<JSFCoreSigEvents> {

    public JSFSigEventsEmitter(@Nonnull MessageExtractor messageExtractor, @Nonnull JSFCoreSigEvents emitter) {
        super(emitter, messageExtractor);
    }
}

...其中:

  • SigEventsEmitter被参数化为:public class SigEventsEmitter<T extends SigEvents> {
  • JSFCoreSigEventspublic interface JSFCoreSigEvents extends CoreSigEvents,它本身就是public interface CoreSigEvents extends SigEvents,这是我的构建器的基接口

在给定的上下文中,当我try 这样使用构建器时:

    SigEventsEmitter<JSFCoreSigEvents> sigEventEmitter = SigEventFactory.newSigEventEmitterBuilder()
            .forEmitter(JSFCoreSigEvents.class, ((jsfCoreSigEvents, messageExtractor) -> new JSFSigEventsEmitter(messageExtractor, (JSFCoreSigEvents) jsfCoreSigEvents)))
            .buildEmitter();

...我在lambda表达式的返回中得到一个错误,特别是:Bad return type in lambda expression: JSFSigEventsEmitter cannot be converted to SigEventsEmitter<SigEvents>.

我知道这是因为类型擦除造成的,但我不明白为什么,尤其是如何修复设计.

我的forEmitter中的TT extends SigEvents的具体类型,我将其作为JSFCoreSigEvents.class传递,BiFunction的返回应该是SigEventsEmitter<JSFCoreSigEvents>,这是我的JSFSigEventsEmitter的情况.有什么主意吗?

附注:所有的需要是能够在不相互依赖的模块之间使用这个工厂,这就是为什么我需要建立一个通用的SigEventsSigEventsEmitter合同,可以跨模块使用并通过这个构建器构建.

推荐答案

假设newSigEventEmitterBuilder是返回Builder<T>的泛型方法,则编译器错误是由于Java无法正确推断T是什么引起的.按照变量类型的建议,您希望TJSFCoreSigEvents,但是推理只产生它的界限SigEvents作为结果.

Java看不到这一点,因为newSigEventEmitterBuilder是一系列调用中的第一个.在推断链中最后一个调用的类型参数时,该语言只考虑目标类型(例如,要赋值的变量的类型).

解决此问题的一种简单方法是只显式指定类型参数:

SigEventFactory.<JSFCoreSigEvents>newSigEventEmitterBuilder()
    // and so on...

在将泛型方法链接在一起的其他情况下,这种情况经常发生,比如Lombok's @BuilderComparator.comparing等.

Java相关问答推荐

Cucumber TestNG Assert失败,出现java. lang. Numbercycle异常

Oracle DUAL表上使用DDL时jOOQ问题的解析'

通过合并Akka Streams中的多个慢源保持订购

只需最少的代码更改即可将版本号标记添加到日志(log)

通过移动一个类解决了潜在的StubbingProblem.它怎麽工作?

Spring和可编辑";where";@Query

带错误BER验证的itext8签名返回pdf

从ActiveMQ Classic迁移到ActiveMQ Artemis需要进行哪些客户端更改?

Java构造函数分支

如何将Java文档配置为在指定的项目根目录中生成?

buildDir:File!&#的getter解决方案是什么?39.被抛弃

如何在列表(链表)中插入一个新 node (作为prelast)

对从Spring Boot 3.1.5升级到3.2.0的方法的查询验证失败

本机方法(JNI)总是编译的吗?

Java KeyListener不工作或被添加

在ECLIPSE上的M1 Pro上运行JavaFX的问题

保持标题窗格的箭头可见,即使设置为不可折叠

using case default on switch语句返回;预览特征切换中的模式匹配仅在源级别20及以上的情况下可用;

在外部类和内部类之间,当调用外部类内部或外部的主方法时,它们的静态初始化程序的运行顺序不同

为什么当我输入变量而不是直接输入字符串时,我的方法不起作用?