Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using abstract init() function in abstract class's constructor

Tags:

java

I have something like this:

    public abstract class Menu {
     public Menu() {
      init();
     }

     protected abstract void init();

     protected void addMenuItem(MenuItem menuItem) {
      // some code...
     }
    }

    public class ConcreteMenu extends Menu {
     protected void init() {
      addMenuItem(new MenuItem("ITEM1"));
      addMenuItem(new MenuItem("ITEM2"));
      // ....
     }
    }

//Somewhere in code
Menu menu1 = new ConcreteMenu();

As you can see superclass's init method is abstract and is called by constructor automatically after object is created.

I'm curious if i can run into some sort of problems with code like this, when i need to create some object of this kind whose structure wont't be changed in time.

Would be any approach better? It works in Java, but will it work in C++ and possibly ActionScript?

Thank you for answer.

like image 861
Jarek Avatar asked Jul 27 '10 10:07

Jarek


1 Answers

DO NOT INVOKE OVERRIDEABLE METHODS FROM THE CONSTRUCTOR.

A quote from Effective Java 2nd Edition, Item 17: Design and document for inheritance, or else prohibit it:

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 be 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.

Here's an example to illustrate:

public class ConstructorCallsOverride {
    public static void main(String[] args) {
        abstract class Base {
            Base() { overrideMe(); }
            abstract void overrideMe(); 
        }
        class Child extends Base {
            final int x;
            Child(int x) { this.x = x; }
            @Override void overrideMe() {
                System.out.println(x);
            }
        }
        new Child(42); // prints "0"
    }
}

Here, when Base constructor calls overrideMe, Child has not finished initializing the final int x, and the method gets the wrong value. This will almost certainly lead to bugs and errors.

Related questions

  • Calling an Overridden Method from a Parent-Class Constructor
  • State of Derived class object when Base class constructor calls overridden method in Java

See also

  • FindBugs - Uninitialized read of field method called from constructor of superclass
like image 101
polygenelubricants Avatar answered Oct 05 '22 01:10

polygenelubricants