我正在尝试创建许多具有继承层次结构的类。为了实例化这些类,我想使用构建器,但我也想重写这些构建器中的一些方法。既然有继承,我就用@SuperBuilder来实现。但是加入泛型,一切都变得有点混乱,我不确定如何正确修复它。
我有一个基类定义为:
@SuperBuilder
public class Base<T> {
protected T payload;
protected String name;
protected String attribute;
}
现在我想创建一个新类来扩展这个类,但会绑定有效负载属性的类型,并设置一些默认值,所以我将其定义为:
@SuperBuilder
public class ChildA<T extends Payload> extends Base<T> {
public abstract static class ChildABuilder
<T extends Payload, C extends ChildA<T>, B extends ChildA.ChildABuilder<T, C, B>>
extends Base.BaseBuilder<T, C, B> {
ChildABuilder() {
super.name("CHILD A");
}
@Override
public B payload(T payload) {
return super.payload(payload).attribute(payload.attribute());
}
}
}
但这会抛出一个错误,说“两种方法都有相同的擦除,但都不隐藏对方”。所以我将父级
@SuperBuilder
更改为@SuperBuilder(builderMethodName = "baseBuilder")
,解决了这个问题。 (我们假设 Payload 也有一个“attribute”属性,只是为了说明我的问题)。
但是,我无法实际构建一个实例。尝试做以下事情:
ChildA<PayloadChild> childA = ChildA.<PayloadChild>builder()
.payload(new PayloadChild())
.build();
导致
.payload(new PayloadChild())
出现问题,指出需要 T,但提供了 PayloadChild。 (假设 PayloadChild 扩展了 Payload)。
我尝试过“delomboking”代码,并制作了一个有点功能的类。但我在构建基类实例时仍然遇到问题,例如用于测试,并且我不认为 delomboking 应该是解决方案。
我做错了什么?需要进行哪些更改才能发挥作用?
编辑1: 在 @Sweeper 的评论之后,我意识到我的代码确实有效。引发错误的是 IntelIJ IDE(或 Lombok 插件),但它实际上可以编译并运行。 我暂时保留这个问题,以防有人有一些解决方法或让 IDE 不抱怨的东西。
您遇到的第一个问题(“...具有相同的擦除,但两者都没有隐藏另一个”)是由于Java语言的限制。静态方法不能被重写,只能互相隐藏。在这种情况下,
builder()
子类中的 ChildA
方法不会隐藏 Base
超类中的方法,因为它们具有不同的签名。但是,编译器无法静态地确定您要调用哪个方法(因为“它们具有相同的擦除”,即删除类型参数后它们看起来完全相同)。
您已经找到了解决方案:重命名其中一个
builder()
方法。这是一个有效的解决方案。但是,从您的代码来看,它似乎并不打算直接使用 Base
类。如果是这样的话,可能会更好
builder()
或 删除
Base
类中的
@SuperBuilder(builderMethodName = "")
Base
类抽象。通过这种方式,您将不会有额外的静态
builder()
方法,如果开发人员在自动完成中看到它,可能会感到困惑。
您描述的第二个问题实际上只出现在IntelliJ中,但在Eclipse中或使用
javac
编译时不会出现。考虑提交错误。