Utk*_*tku 6 java oop inheritance
我想generateId()在抽象超类的构造函数中调用抽象方法,其中此抽象方法依赖于相应子类的某些字段.为清楚起见,请考虑以下代码:
抽象类: SuperClass
public abstract class SuperClass {
protected String id;
public SuperClass() {
generateId();
}
protected abstract void generateId();
}
Run Code Online (Sandbox Code Playgroud)
子类: 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
}
}
Run Code Online (Sandbox Code Playgroud)
子类: 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
}
}
Run Code Online (Sandbox Code Playgroud)
但是,子类构造函数不起作用,因为它super();必须是构造函数中的第一个语句.
OTOH,如果我super();在子类的构造函数的第一条语句,那么我就不能打电话generateId()的SuperClass.因为generateId()在子类中使用字段,这些字段必须在使用之前初始化.
在我看来,"解决"这个问题的唯一方法是:删除generateId()超类中的调用.generateId()在每个子类的构造函数的末尾调用.但这会导致代码重复.
那么有没有办法解决这个问题而不重复我的代码?(也就是说,不调用每个子类generateId()的构造函数的末尾?)
正如@GuillaumeDarmont指出的那样,在构造中使用可覆盖的方法是不好的做法.
您希望强制超类id由子类初始化,因此更改构造函数:
public abstract class SuperClass {
protected String id;
public SuperClass(String id) {
this.id = id;
}
}
Run Code Online (Sandbox Code Playgroud)
此外,您可能希望更改generateId()为静态方法,因为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
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:由于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
}
}
Run Code Online (Sandbox Code Playgroud)
两个解决方案之间的区别在于何时将计算id:在对象初始化时,或第一次请求id.这就是@Turing85正在讨论的内容.