我想在一个抽象父类(super class)的构造函数中调用一个抽象方法generateId()
,其中该抽象方法取决于各个子类的某些字段。为了清楚起见,请考虑以下代码:
抽象类:SuperClass
public abstract class SuperClass {
protected String id;
public SuperClass() {
generateId();
}
protected abstract void generateId();
}
子类:
Sub1
public class Sub1 extends SuperClass {
private SomeType fieldSub1;
public Sub1(SomeType fieldSub1) {
this.fieldSub1 = fieldSub1;
super();
}
protected void generateId() {
// Some operations that use fieldSub1
}
}
子类:
Sub2
public class Sub2 extends SuperClass {
private SomeOtherType fieldSub2;
public Sub2(SomeOtherType fieldSub2) {
this.fieldSub2 = fieldSub2;
super();
}
protected void generateId() {
// Some operations that use fieldSub2
}
}
但是,子类构造函数将不起作用,因为
super();
必须是构造函数中的第一条语句。OTOH,如果我将
super();
设为子类的构造函数中的第一条语句,则将无法在generateId()
中调用SuperClass
。因为generateId()
使用子类中的字段,所以在使用之前必须在其中初始化这些字段。对我来说,“解决”此问题的唯一方法是:在父类(super class)中删除对
generateId()
的调用。在每个子类的构造函数的末尾放置对generateId()
的调用。但这会导致代码重复。那么有什么方法可以解决这个问题而不重复我的代码吗? (就是说,没有在每个子类的构造函数的末尾调用
generateId()
吗?) 最佳答案
正如@GuillaumeDarmont指出的那样,在构造中使用可重写的方法是不好的做法。
您想让父类(super class)id
由子类初始化,因此更改构造函数:
public abstract class SuperClass {
protected String id;
public SuperClass(String id) {
this.id = id;
}
}
另外,您可能希望将
generateId()
更改为静态方法,因为在调用父类(super class)构造函数之前无法引用this
:public class Sub1 extends SuperClass {
private SomeType fieldSub1;
public Sub1(SomeType fieldSub1) {
super(generateId(fieldSub1));
this.fieldSub1 = fieldSub1;
}
private static String generateId(SomeType fieldSub1) {
// Some operations that use fieldSub1
}
}
编辑:由于
SuperClass
不知道如何计算id
,但是您要强制使用它的ID,因此上面的解决方案是您的选择之一。另一种选择是:public abstract class SuperClass {
private String id;
public String getId() {
if (id == null) { id = generateId(); }
return id;
}
protected abstract String generateId();
}
public class Sub1 extends SuperClass {
private SomeType fieldSub1;
public Sub1(SomeType fieldSub1) {
this.fieldSub1 = fieldSub1;
}
@Override protected String generateId() {
// Some operations that use fieldSub1
}
}
两种解决方案之间的区别大约是:在计算 ID时:在对象初始化时,或者在第一次请求ID时。这就是@ Turing85在讨论的内容。