2

Several times I thought it will be good to have overridable constructor in Java.

"Overridable" means the logic of construction can be overriden and/or extended in descending classes in the same way it is possible to override normal methods, i.e. with ability to call parent method AFTER the child.

This task can be formulated as to have a method, say, called init() which is called at construction time, but only in the last constructor of the stack.

Like:

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"

   }
}

The obvious way is to write

public static void main(String[] args) {

      new A().init();
      new B().init();
      new C().init();

   }

but this doesn't guarantee init() is not forgotten to call.

Is it possible to do somehow?

UPDATE

It is not known at design time, which class will be "last". It is expected, that class tree will be developed in future.

UPDATE 2

Here is the solution with reflection and constructor code requirement to call currentStage() at the end:

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"

   }

Is it possible to write simpler?

Dims
  • 47,675
  • 117
  • 331
  • 600
  • You don't show why you think those methods should be called by the constructors. – ChiefTwoPencils Sep 13 '16 at 08:14
  • What's the problem with literally calling `init` in `C` constructor? What's the problem with putting `super.init();` in each overriding method? – default locale Sep 13 '16 at 08:15
  • 1
    @defaultlocale if I put `init()` in `C` constructor then it won't be called when constructing `A` and `B`. There is no problem to put `super.init()` into anywhere, but how this will help? – Dims Sep 13 '16 at 08:18
  • BTW, constructors are not inherited nor overriden in Java. – ChiefTwoPencils Sep 13 '16 at 08:27
  • @ChiefTwoPencils I know this, but I wan't to overcome this somehow – Dims Sep 13 '16 at 08:34
  • 2
    Override methods called in the constructor is possible but it is considered a bad design and could cause several problems, see this question for details [whats-wrong-with-overridable-method-calls-in-constructors](http://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors) – David SN Sep 13 '16 at 08:35
  • @DavidSN I know these mantras. I just wish to solve these problems – Dims Sep 13 '16 at 08:36
  • 1
    Now it's getting complicated. Can you show us the reasons behind this design? Also, this question contains several suggestions: http://stackoverflow.com/questions/27453105/call-a-method-after-the-constructor-has-ended – default locale Sep 13 '16 at 08:43
  • As a slight improvement to your Update 2, I'd suggest to replace `A.class`, `B.class`, etc by `MethodHandles.lookup().lookupClass()` respectively. It is equivalent, but you can copy it from one constructor to the next, without the need to adapt it. See [here](https://stackoverflow.com/questions/936684/getting-the-class-name-from-a-static-method-in-java/29477085#29477085) or [here](https://stackoverflow.com/questions/29492993/something-like-this-class-instead-of-classname-class) which I think are closely related problems. – Sebastian Aug 10 '22 at 15:49

4 Answers4

2

Constructors shouldn't call overridable methods. If invoking of such method is necessary the better solution is makes constructors protected and provide static factory methods:

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"

   }
}

Edit More explanation: Such solution provide benefits but also drawbacks. You should to provide a contract for classes (i.e. in Javadoc) that sub-classes that extends your class should follow this standard of objects creation. Also it creates more code. The profit is that objects created in that way:

C obj = C.newInstance() 

...are always fully initialized and there is no need to remember for call init() method explicite.

Remember that it also will be the only method for create object outside the class' package (constructor won't be available), but inside same package constructor will be still available (protected methods are available inside same package)

Jakub Ch.
  • 3,577
  • 3
  • 24
  • 43
1

In Java, when child class is instantiated, default constructor of parent class is always invoked (unless any other constructor is specified). Now, if you need to have a common code that needs to be executed for all the classes, it's recommended to put it in constructor. However, if you want something to be executed only in the last class in the hierarchy then (a) you can write it into the last constructor itself or (b) write an initialisation block, below example demonstrates this:

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");
    }
}
Darshan Mehta
  • 30,102
  • 11
  • 68
  • 102
1

Just change your a class constructor like this, each object init method will call by calling this.init(), you required to change just most upper class constructor.Because at time of object creation parent class constructor will definitely call

public class Test {
    public static class A {

        public A() {

            this.init();
        }

        void init() {
            System.out.println("Called in A");
        }
    }

    public static class B extends A {

        @Override
        void init() {
            System.out.println("Called in B");
        }
    }

    public static class C extends B {

        @Override
        void init() {
            System.out.println("Called in C");
        }
    }

    public static void main(String[] args) {

        new A(); // should "Called in A" printed
        new B(); // should "Called in B" printed
        new C(); // should "Called in C" printed

    }
}
Jekin Kalariya
  • 3,475
  • 2
  • 20
  • 32
  • Can you write entire example? I don't understand, why will it work? – Dims Sep 13 '16 at 08:22
  • Sorry, you are right, my code was bad example. See my update please. – Dims Sep 13 '16 at 08:32
  • 4
    According to item 17 in Joshua's Bloch "Effective Java" your example is poor designed: _There are a few more restrictions that a class must obey to allow inheritance. Constructors must not invoke overridable methods, directly or indirectly. If you violate this rule, program failure will result. The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will get invoked before the subclass constructor has run. If the overriding method depends on any initialization performed by the subclass constructor, the method will not behave as expected._ – Jakub Ch. Sep 13 '16 at 08:37
  • Dims if you have not decide which class would be top parent then it would be difficult to achieve this – Jekin Kalariya Sep 13 '16 at 08:40
  • jakub, I agree with your point 'Constructors must not invoke overridable methods', but OP has already declare common method in all class , so I have not thought to change his all design – Jekin Kalariya Sep 13 '16 at 08:41
  • @JakubCh. I know this and this is the question: how to overcome these limitations? If `init()` would be called last, it won't harm anything, because everything will be constructed at the moment. – Dims Sep 13 '16 at 08:46
  • @Dims - if you are absolutely sure that init() would be called last there is no problem. But if you aren't - maybe consider to make constructors protected and provide static factory methods, that first create object and then do initialization? – Jakub Ch. Sep 13 '16 at 08:50
  • @JakubCh. this is the question: how to call `init()` last? – Dims Sep 13 '16 at 08:56
  • @Dims I posted my answer – Jakub Ch. Sep 13 '16 at 09:01
0

Use super.init() for this to call root parent class init() .

Abhilash Arjaria
  • 142
  • 2
  • 10