在Java中模拟构造函数覆盖?

时间:2016-09-13 08:11:38

标签: java inheritance constructor initialization

我曾多次认为在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"

   }

是否可以写得更简单?

4 个答案:

答案 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()。