我曾多次认为在Java中使用可覆盖的构造函数会很好。
“Overridable”意味着构造的逻辑可以在降序类中被覆盖和/或扩展,就像可以覆盖普通方法一样,即能够在孩子之后调用父方法。
这个任务可以表示为有一个方法,比如称为init()
,它在构造时调用,但只在堆栈的最后一个构造函数中调用。
像:
public class InitializationOverride {
public static class A {
A() {
System.out.println("Constructor of A");
}
void init() {
System.out.println("Init of A");
}
}
public static class B extends A {
B() {
System.out.println("Constructor of B");
}
@Override
void init() {
System.out.println("Init of B");
}
}
public static class C extends B {
C() {
System.out.println("Constructor of C");
}
@Override
void init() {
System.out.println("Init of C");
}
}
public static void main(String[] args) {
new A(); // should print "Constructor of A, Init of A"
new B(); // should print "Constructor of A, Constructor of B, Init of B"
new C(); // should print "Constructor of A, Constructor of B, Constructor of C, Init of C"
}
}
显而易见的方法是写
public static void main(String[] args) {
new A().init();
new B().init();
new C().init();
}
但这并不能保证init()
不会忘记打电话。
有可能以某种方式吗?
更新
在设计时不知道哪个班级将是“最后”。预计将来会开发类树。
更新2
这是具有反射和构造函数代码要求的解决方案,最后调用currentStage()
:
public class InitializationOverride {
public static class A {
A() {
System.out.println("Constructor of A");
currentStage(A.class);
}
void currentStage(Class<?> cls) {
if( cls == getClass() ) {
init();
}
}
void init() {
System.out.println("Init of A");
}
}
public static class B extends A {
B() {
System.out.println("Constructor of B");
currentStage(B.class);
}
@Override
void init() {
System.out.println("Init of B");
}
}
public static class C extends B {
C() {
System.out.println("Constructor of C");
currentStage(C.class);
}
@Override
void init() {
System.out.println("Init of C");
}
}
public static void main(String[] args) {
new A(); // should print "Constructor of A, Init of A"
new B(); // should print "Constructor of A, Constructor of B, Init of B"
new C(); // should print "Constructor of A, Constructor of B, Constructor of C, Init of C"
}
是否可以写得更简单?
答案 0 :(得分:2)
构造函数不应该调用可覆盖的方法。如果需要调用此类方法,则更好的解决方案是使构造函数受到保护并提供静态工厂方法:
public class InitializationOverride {
public static class A {
protected A() {
System.out.println("Constructor of A");
}
public static A newInstance(){
A a = new A();
a.init();
return a;
}
protected void init() {
System.out.println("Init of A");
}
}
public static class B extends A {
protected B() {
System.out.println("Constructor of B");
}
public static B newInstance(){
B b = new B();
b.init();
return b;
}
@Override
protected void init() {
System.out.println("Init of B");
}
}
public static class C extends B {
protected C() {
System.out.println("Constructor of C");
}
public static C newInstance(){
C c = new C();
c.init();
return c;
}
@Override
protected void init() {
System.out.println("Init of C");
}
}
public static void main(String[] args) {
A.newInstance(); // should print "Constructor of A, Init of A"
B.newInstance(); // should print "Constructor of A, Constructor of B, Init of B"
C.newInstance(); // should print "Constructor of A, Constructor of B, Constructor of C, Init of C"
}
}
修改强> 更多解释:这种解决方案提供了好处,但也有缺点。您应该为类提供合同(即在Javadoc中),扩展您的类的子类应遵循此对象创建标准。它还会创建更多代码。利润是以这种方式创建的对象:
C obj = C.newInstance()
...总是被完全初始化,并且不需要记住调用init()方法explicite。
请记住,它也是在类'包之外创建对象的唯一方法(构造函数将不可用),但在同一个包构造函数中仍然可用(受保护的方法在同一个包中可用)
答案 1 :(得分:1)
只需改变你的类构造函数,每个对象的init方法都会通过调用async
来调用,你只需要改变大多数上层构造函数。因为在创建对象时父类构造函数肯定会调用
this.init()
答案 2 :(得分:0)
在Java中,当实例化子class
时,始终调用父类的默认constructor
(除非指定了任何其他constructor
)。现在,如果您需要为所有classes
创建一个需要执行的公共代码,建议将其放在constructor
中。但是,如果您希望仅在层次结构中的最后class
执行某些操作,则(a)您可以将其写入最后的constructor
本身或(b)编写初始化块,下面的示例演示这样:
public class Test extends Test2{
public Test(){
System.out.println("In test");
System.out.println("Init last");
}
{
System.out.println("Init");
}
public static void main(String[] args) {
new Test();
}
}
class Test2{
public Test2(){
System.out.println("In test 2");
}
}
答案 3 :(得分:0)
使用super.init()来调用root父类init()。