假设我有一个Java类
abstract class Base {
abstract void init();
...
}
而且我知道每个派生类init()
构造后都必须调用。我当然可以在派生类的构造函数中简单地调用它:
class Derived1 extends Base {
Derived1() {
...
init();
}
}
class Derived2 extends Base {
Derived2() {
...
init();
}
}
但这严重破坏了“不要重复自己”的原则(并且将有的许多子类Base
)。当然,该init()
调用不能进入Base()
构造函数,因为它执行得太早了。
任何想法如何绕过这个问题?我也很高兴看到Scala解决方案。
更新:这是工厂方法的通用版本:
interface Maker<T extends Base> {
T make();
}
class Base {
...
static <T extends Base> T makeAndInit(Maker<T> maker) {
T result = maker.make();
result.init();
return result;
}
}
更新2:这个问题基本上是“如何为构造函数使用模板方法”?答案似乎是,“可以,但这是个坏主意”。因此,我可以改为使用模板工厂(模板方法+抽象工厂)。
发生什么事了init()
?更好的设计可能会完全消除该方法,或者至少放宽该方法在子类的构造函数之后执行的要求。init()
在构造函数完成之前,请确保不会使正在构造的对象对任何其他线程可见,因为这会导致并发错误。
作为一种(丑陋的)选择,抽象方法可以由子类实现为伪构造函数:
abstract class Base {
Base() {
ctor();
init();
}
abstract void ctor();
abstract void init();
}
主要内容:构造函数的调用顺序,基类构造函数调用规则前面我们说基类的成员函数可以被继承,可以通过派生类的对象访问,但这仅仅指的是普通的成员函数, 类的构造函数不能被继承。构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,不能成为派生类的构造函数,当然更不能成为普通的成员函数。 在设计派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数完成,但是大部分基类都有 private 属性的成员变量,它们在派生类中无法
由于派生类继承了其基类的成员,所以在建立派生类的实例对象时,必须调用基类的构造函数来初始化派生类对象的基类成员。派生类的构造函数既可以隐式调用基类的构造函数,也可以在派生类的构造函数中通过给基类提供初始化值(利用了前面所讲过的成员初始化值语法)显式地调用基类的构造函数。 派生类不继承基类的构造函数和赋值运算符,但是派生类的构造函数和赋值运算符能调用基类的构造函数和赋值运算符。 派生类的构造函数总是
我认为这段代码是错误的,因为jvm可以选择在完成构造函数之前运行。 那么,当构造函数完成时,如何确保另一个线程始终执行?
问题内容: 请参考下面的Java代码: 看到的输出是: 我认为发生var = 0是因为派生对象已初始化一半;类似于乔恩·斯基特在这里说的话 我的问题是: 如果尚未创建Derived类对象,为什么要调用重写的方法? var在什么时间点分配值为0? 是否有任何需要这种行为的用例? 问题答案: 该对象 已 被创建-它只是在构造函数尚未运行。对象的类型在创建后即刻就不会在Java中更改,这发生在所有构造函
问题内容: 我有以下代码片段: 执行代码时出现异常: 我不明白为什么会有和例外。有人可以帮助我理解吗? 您可以在此处检查代码。 问题答案: 创建一个对象,这意味着首先调用其超类构造函数,然后依次调用-但您已覆盖它,因此它是该方法的子版本。在该方法中,您调用尚未初始化的。 结论:在构造函数中调用可重写方法几乎从来不是一个好主意。
问题内容: 如果我有一个像这样的构造函数: 然后,我如何在与构造函数相同的类中的方法中使用变量c和d,因为尝试仅在方法中使用变量名似乎不起作用? 问题答案: 实际上,您的代码将无法编译- 无效。 我认为您的意思是:- 。 然后我如何在与构造函数相同的类中的方法中使用变量c和d 您不能这样做,因为您已将它们声明为局部变量,其范围在构造函数结束执行时终止。 您应该将它们声明为实例变量。