如何避免继承类构造方法重复输入父类参数实现自动传递
嘿,这个问题我太有共鸣了——多层继承里反复复制粘贴父类构造的参数,不仅写着烦,后期改参数的时候更是要一层层调整,简直是维护噩梦!
Java本身确实没有你设想的那种C(super(), int i5, int i6)语法,因为构造方法必须显式调用父类构造器,而且必须明确传递所需参数。不过别担心,有好几种办法能帮你大幅减少重复代码的工作量,下面给你逐个举例说明:
1. 用Lombok的@SuperBuilder(最省心的方案)
如果你能引入Lombok这个工具库,那这绝对是最优解。@SuperBuilder注解可以自动生成支持父类字段的Builder模式,完全不用手动写构造参数和super调用。
给你的例子改造一下:
import lombok.experimental.SuperBuilder; abstract class A { int int1; int int2; A(int i1, int i2) { int1 = i1; int2 = i2; } } @SuperBuilder class B extends A { int int3; int int4; B(int i1, int i2, int i3, int i4) { super(i1, i2); int3 = i3; int4 = i4; } } @SuperBuilder class C extends B { int int5; int int6; C(int i1, int i2, int i3, int i4, int i5, int i6) { super(i1, i2, i3, i4); int5 = i5; int6 = i6; } }
现在创建C对象时,你可以用Builder链式调用,完全不用关心父类参数的传递逻辑:
C c = C.builder() .int1(1) .int2(2) .int3(3) .int4(4) .int5(5) .int6(6) .build();
甚至如果你想保留原来的new C(1,2,3,4,5,6)调用方式,Lombok也能自动生成全参构造,你不用手动写那些重复的参数。
2. 手动实现Builder模式(不依赖第三方库)
如果不能用Lombok,手动写Builder模式也能解决问题——虽然要多写点模板代码,但胜在原生支持,不依赖任何库。
示例代码:
abstract class A { int int1; int int2; A(int i1, int i2) { int1 = i1; int2 = i2; } // A的Builder基类 protected static abstract class ABuilder<T extends ABuilder<T>> { protected int int1; protected int int2; public T int1(int int1) { this.int1 = int1; return self(); } public T int2(int int2) { this.int2 = int2; return self(); } protected abstract T self(); public abstract A build(); } } class B extends A { int int3; int int4; B(int i1, int i2, int i3, int i4) { super(i1, i2); int3 = i3; int4 = i4; } // B的Builder继承ABuilder public static class Builder extends ABuilder<Builder> { private int int3; private int int4; public Builder int3(int int3) { this.int3 = int3; return this; } public Builder int4(int int4) { this.int4 = int4; return this; } @Override protected Builder self() { return this; } @Override public B build() { return new B(int1, int2, int3, int4); } } } class C extends B { int int5; int int6; C(int i1, int i2, int i3, int i4, int i5, int i6) { super(i1, i2, i3, i4); int5 = i5; int6 = i6; } // C的Builder继承B.Builder public static class Builder extends B.Builder { private int int5; private int int6; public Builder int5(int int5) { this.int5 = int5; return this; } public Builder int6(int int6) { this.int6 = int6; return this; } @Override public C build() { return new C(int1, int2, int3, int4, int5, int6); } } }
现在创建C对象就可以这样:
C c = new C.Builder() .int1(1) .int2(2) .int3(3) .int4(4) .int5(5) .int6(6) .build();
虽然写Builder时要多费点功夫,但后续创建对象和维护时会轻松很多——改父类参数只需要调整对应的Builder,不用一层层修改构造方法。
3. 用Java 16+的记录类(适合不可变类场景)
如果你的类是不可变的(字段都是final),Java 16引入的记录类(Record)能帮你省去大量构造和字段的代码。不过要注意,记录类只能继承java.lang.Record,不能继承普通抽象类,所以如果你的继承链可以调整为组合或者父类也是记录类的话,这个方案很合适。
比如调整你的例子(用接口代替抽象类):
interface A { int int1(); int int2(); } record B(int int1, int int2, int int3, int int4) implements A {} record C(int int1, int int2, int int3, int int4, int int5, int int6) extends B { public C(int int1, int int2, int int3, int int4, int int5, int int6) { super(int1, int2, int3, int4); } }
这样你还是可以用new C(1,2,3,4,5,6)创建对象,而且不用手动写字段和大部分构造代码,记录类会自动帮你生成。
总结
Java本身没有直接省略父类构造参数的语法,但通过Lombok、手动Builder模式或者记录类,都能有效减少重复代码的工作量。其中Lombok的@SuperBuilder是最省心的,几乎零手动代码;如果不能用第三方库,手动Builder模式是原生方案里的最佳选择;记录类则适合不可变类的场景。
内容的提问来源于stack exchange,提问作者Potato

