如何在龙目岛调用超级构造函数
Posted
技术标签:
【中文标题】如何在龙目岛调用超级构造函数【英文标题】:how to Call super constructor in Lombok 【发布时间】:2015-06-26 17:13:26 【问题描述】:我有课
@Value
@NonFinal
public class A
int x;
int y;
我还有一个 B 班
@Value
public class B extends A
int z;
lombok 抛出错误,说它找不到 A() 构造函数,显式调用它我想要 lombok 做的是给类 b 注释,以便它生成以下代码:
public class B extends A
int z;
public B( int x, int y, int z)
super( x , y );
this.z = z;
我们在 Lombok 中是否有注释可以做到这一点?
【问题讨论】:
【参考方案1】:这在龙目岛是不可能的。虽然这将是一个非常好的特性,但它需要解析才能找到超类的构造函数。超类只有在 Lombok 被调用时才知道名称。使用 import 语句和类路径来查找实际的类并非易事。而且在编译过程中,你不能只使用反射来获取构造函数列表。
这并非完全不可能,但使用val
和@ExtensionMethod
中的分辨率的结果告诉我们,这很难且容易出错。
披露:我是 Lombok 开发人员。
【讨论】:
@roel-spilker 我们了解其背后的复杂性。但是Lombok能否为构造函数注解提供inConstructor
方法,我们可以指定Lombok在生成的构造函数中注入super
的哪个构造函数?
afterConstructor 也可以做一些自动初始化
@Manu/@Pawel:查看 lombok 增强请求:github.com/peichhorn/lombok-pg/issues/78(当前开放)
还是不行?
@Roel 是否可以制作类似@CopyConstructor
的东西?这样我们就可以用它注释class Base
,并且在class Der extends Base
中,以下内容很简短,很容易手动完成:public Der(Base base, Object extraProp) super(base); this.extraProp = extraProp;
【参考方案2】:
Lombok Issue #78 引用此页面https://www.donneo.de/2015/09/16/lomboks-builder-annotation-and-inheritance/ 并附有这个可爱的解释:
@AllArgsConstructor public class Parent private String a; public class Child extends Parent private String b; @Builder public Child(String a, String b) super(a); this.b = b;
因此,您可以像这样使用生成的构建器:
Child.builder().a("testA").b("testB").build();
official documentation 对此进行了解释,但没有明确指出您可以通过这种方式促进它。
我还发现这与 Spring Data JPA 配合得很好。
【讨论】:
您能否提供一个与 Spring Data JPA 一起使用的示例? 这根本不能回答问题。相反,它是手工完成的,而问题是如何生成它。同时,通过拖拽@Builder让整个事情变得更加混乱,这与问题没有任何关系。 其实这对于那些只想创建继承结构然后使用builder的人来说非常有用。这是我使用#lombok 的 99% 的原因。有时我们只需要手工制作东西就可以让它按照我们想要的方式工作。所以感谢@jj-zabkar 然后;只需编写 self+parent arg 构造函数即可。无需使用构建器 它可以在 STS 和 eclipse 中工作,但是当你生成应用程序的 JAR 文件时,它很可能会失败。我尝试了 Both SuperBuilder, Builder 的继承。两个都失败了。小心!!【参考方案3】:Lombok 1.18 版引入了@SuperBuilder 注解。我们可以使用它以更简单的方式解决我们的问题。
您可以参考https://www.baeldung.com/lombok-builder-inheritance#lombok-builder-and-inheritance-3。
所以在您的子类中,您将需要这些注释:
@Data
@SuperBuilder
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
在你的父类中:
@Data
@SuperBuilder
@NoArgsConstructor
【讨论】:
对于 SuperBuilder,AllArgsConstructor 是否包含来自父子节点的参数?谢谢! 如果结果类中不需要 SuperBuilder,我们无法解决这个问题。尤其是当这个建造者离理想很远的时候。就我而言,我的构建者总是在做深拷贝,龙目岛 - 不。 java:使用对 java.lang.Object 的超级调用生成 equals/hashCode 是没有意义的。【参考方案4】:Lombok 不支持通过创建任何 @Value
注释类 final
(如您所知道的使用 @NonFinal
)来指示的。
我发现的唯一解决方法是自己声明所有成员为 final 并改用 @Data
注释。这些子类需要由 @EqualsAndHashCode
注释,并且需要一个显式的 all args 构造函数,因为 Lombok 不知道如何使用超类的所有 args 之一创建一个:
@Data
public class A
private final int x;
private final int y;
@Data
@EqualsAndHashCode(callSuper = true)
public class B extends A
private final int z;
public B(int x, int y, int z)
super(x, y);
this.z = z;
尤其是子类的构造函数,对于有很多成员的超类来说,解决方案有点凌乱,抱歉。
【讨论】:
你能解释一下为什么“子类需要用@EqualsAndHashCode
注释”吗? @Data
中不包含这个注解吗?谢谢 :)
@GerardB @Data
也创建了 equals() 和 hashCode() 但不关心任何继承。为了确保使用超类 equals() 和 hashCode(),您需要使用 callSuper 显式生成【参考方案5】:
对于有很多成员的超类,我建议你使用@Delegate
@Data
public class A
@Delegate public class AInner
private final int x;
private final int y;
@Data
@EqualsAndHashCode(callSuper = true)
public class B extends A
private final int z;
public B(A.AInner a, int z)
super(a);
this.z = z;
【讨论】:
这个方法很有意思,赞!@Delegate
是 @Target(ElementType.FIELD, ElementType.METHOD)
。 AInner
应该是A
中的字段。【参考方案6】:
如果子类的成员比父类多,则可以做得不是很干净,但方法很短:
@Data
@RequiredArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class User extends BaseEntity
private @NonNull String fullName;
private @NonNull String email;
...
public User(Integer id, String fullName, String email, ....)
this(fullName, email, ....);
this.id = id;
@Data
@AllArgsConstructor
abstract public class BaseEntity
protected Integer id;
public boolean isNew()
return id == null;
【讨论】:
不应轻易保护实例变量,因为它很可能违反了面向对象的原则。【参考方案7】:作为一个选项,您可以使用com.fasterxml.jackson.databind.ObjectMapper
从父类初始化子类
public class A
int x;
int y;
public class B extends A
int z;
ObjectMapper MAPPER = new ObjectMapper(); //it's configurable
MAPPER.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
MAPPER.configure( SerializationFeature.FAIL_ON_EMPTY_BEANS, false );
//Then wherever you need to initialize child from parent:
A parent = new A(x, y);
B child = MAPPER.convertValue( parent, B.class);
child.setZ(z);
如果需要,您仍然可以在 A 和 B 上使用任何 lombok
注释。
【讨论】:
这不适用于 OP 的@Value
,因为如果没有无参数构造函数,Jackson 将失败。即使它确实有效,序列化为 json 并在每个 new
上反序列化也是疯狂的。
不幸的是,这不是问题的答案(是否有任何 Lombok 注释可以解决所描述的问题?)
@LarsGendner 是的,我猜这不是一个直接的答案。但这是我在等待来自 lombok 的正确注释时使用的解决方案。以上是关于如何在龙目岛调用超级构造函数的主要内容,如果未能解决你的问题,请参考以下文章