1

if it is possible please make this sentence clear for me

here, the author said:

Do not call overridable methods from constructors. When creating a subclass object, this could lead to an overridden method being called before the subclass object is fully initialized. Recall that when you construct a subclass object, its constructor first calls one of the direct superclass’s constructors. If the superclass constructor calls an overridable method, the subclass’s version of that method will be called by the superclass constructor—before the subclass constructor’s body has a chance to execute.

i can't understand that how it can be possible to call a subclass's version of the overridable method in the superclass's constructor

TnX

hamid_c
  • 849
  • 3
  • 11
  • 29

3 Answers3

3

You have to first make a distinction between instantiation and initialization. Instantiation is the process of creating an instance of a type (allocating the space for it and getting a reference to that space). Initialization is the process of setting the state of the instance to its initial value.

Take the following type hierarchy:

class Foo { 
    public Foo() {}
}
class Bar extends Foo {
    public Bar() {super();}
}

New instance creation expressions

new Bar();

cause instantiation and initialization. Instantiation happens first. Java creates an instance of concrete type Bar.

Then initialization needs to take place. In an inheritance hierarchy, the initialization follows the same hierarchy, but top to bottom.

Object
   |
  Foo 
   |
  Bar

The constructor for Object runs first to initialize the state that is defined as part of Object, then the constructor for Foo is run to initialize the state that is defined as part of Foo and finally the constructor for Bar is run to initialize the state defined in Bar. Your instance is still of type Bar. So polymorphism still applies. If you invoke an instance method and that method is overriden somewhere lower in the hierarchy, that implementation will be invoked.

That's what that quote is referring to. It's dangerous. Read more here:

What's wrong with overridable method calls in constructors?

Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
2

To illustrate the reason this is a bad idea with some (simplistic) code, consider these two classes:

class Greeter {
    protected Greeter() {
        printHello();
    }

    protected void printHello() {
        System.out.println("Hello");
    }
}

Looks simple enough, it prints Hello whenever you instantiate it. Now lets extend it:

class NamedGreeter extends Greeter {
    private String name;

    public NamedGreeter(String name) {
        this.name = name;
    }

    @Override
    protected void printHello() {
        System.out.println("Hello " + name);
    }
}

The intent is clearly to have the NamedGreeter greet you by name when instantiated, but in fact it will always print Hello null because the super constructor is called first when the NamedGreeter is instantiated.

Thanks to how polymorphism works, any time the printHello() method is called on a NamedGreeter (even if that call is from within the Greeter class) the implementation in NamedGreeter will be called. Calling that method from within the constructor of the parent class means that even if the child class extends it then no fields defined by the child will be initialized, simply because it's not possible to do anything in the child constructor (like initialize fields) before the parent constructor is called.

1337joe
  • 2,327
  • 1
  • 20
  • 25
1

An example demonstrating that the child method will be invoked:

class Foo {
  static class Parent {
    Parent() {
      someMethod();
    }
    void someMethod() {}
  }

  static class Child extends Parent {
    @Override void someMethod() {
      throw new AssertionError("Invoked");
    }
  }

  public static void main(String[] args) {
    new Child();  // Throws Exception.
  }
}

Output:

Exception in thread "main" java.lang.AssertionError: Invoked
        at Foo$Child.someMethod(Foo.java:16)
        at Foo$Parent.<init>(Foo.java:9)
        at Foo$Child.<init>(Foo.java:14)
        at Foo.main(Foo.java:21)
Andy Turner
  • 137,514
  • 11
  • 162
  • 243