5

Consider the following code segment:

class A{ /* assume static and non static block are here */ }
class B extends A{ /* assume static and non static block are here */ }

In main method,

 new B();

So the order of the initialization would be :

  1. static members initialization for class A
  2. static members initialization for class B
  3. non static members initialization for class A
  4. then execute the code inside constructor A
  5. non static members initialization for class B
  6. then execute the code inside constructor B

Now take a look at this code segment,

class A{
    A(){
        this.m(); //line 1
    }

    void m(){
        System.out.println("A.m()");
    }
  }

  class B extends A{
     void m(){
        System.out.println("B.m()");
    }
  }

In main method,

 new B();

When the code of constructor A is being executed, it can only see the method m in class A since non static members hasn't been initialized yet for class B (according to the order I mentioned). However the result is "B.m()". (method of sub class has been executed) Can someone explain what is happening here(method overridng) considering the order that I have mentioned ?

arshajii
  • 127,459
  • 24
  • 238
  • 287
chathura
  • 3,362
  • 6
  • 41
  • 68
  • [This](http://stackoverflow.com/a/15327631/335858) should bring some clarity, although it's not an exact duplicate. – Sergey Kalinichenko Aug 12 '13 at 15:27
  • 1
    possible duplicate of [Java Class Initialization Order And Overridden Methods](http://stackoverflow.com/questions/18138397/java-class-initialization-order-and-overridden-methods) – Rohit Jain Aug 12 '13 at 15:27
  • 2
    You should **never, Never, NEVER** invoke virtual methods in a constructor / destructor. This is *definite* bad, terrible idea. Invoking `final` instance methods can be *okay*, but I generally consider it a *bad* idea and avoid it when possible. It's such a *terrible* idea that it's covered in Scott Meyer's Effective C++ and while your question *is* about Java, the primary reasons that he gives there apply here to. Don't do it. – jason Aug 12 '13 at 15:27
  • Also you might want to go through the [Relevant JLS Section](http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.5) – Rohit Jain Aug 12 '13 at 15:30

2 Answers2

8

When the code of constructor A is being executed, it can only see the method m in class A since non static members hasn't been initialized yet for class B (according to the order I mentioned).

You're assuming that methods are part of "non-static members" which are initialized. That's not the case - it's really a matter of fields in B being initialized when the A constructor is finished.

As soon as an object is created in Java, its type is set and never changes. Enough space is allocated for all the fields - but the fields are actually initialized from the top of the inheritance hierarchy down.

So yes, if you call an overridden method from a constructor, it will execute in a context where some of the fields it wants to use aren't initialized - so you should avoid doing that if possible.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Jon, Had a quick question, Am wondering if I am taking this in the right direction; The simple way to understand this is, when we have an instance of Class B, that's the active object here. So, new B(), would call the super constructor for A(), where this.m() is equivalent to new B().m() since the method is overridden. – JNL Aug 12 '13 at 18:34
  • @JNL: Well it's not really equivalent to `new B().m()` because it doesn't create a new object... – Jon Skeet Aug 12 '13 at 18:37
  • Jon, Agree it does not create a new object, what I meant was, if I put that correctly, can I say this.m() would be equivalent to objectOfClassB.m() which is called in main, since the main thread which is executing the program has an object of new B(). I hope its not confusing? – JNL Aug 12 '13 at 18:42
  • @JNL: Um, I think so - but I'm not sure it's actively *helpful* :) – Jon Skeet Aug 12 '13 at 18:47
  • Just wanted to clarify. Thank You Jon. Appreciate it. – JNL Aug 12 '13 at 18:52
  • @Jon : So non static members are non static blocks and variables only. Methods are not non static. So during the initialization process only non static blocks and variables are initialized and methods are not initialized. Is it correct? – chathura Aug 13 '13 at 06:52
  • @chathura2020: No, methods etc are members as well - and there are static and non-static methods. But methods don't need to be initialized as part of the initialization of an object. – Jon Skeet Aug 13 '13 at 07:42
  • Ok, So is that the reason, that local variables must be explicitly initialized before they are used.(Since methods are not initialized) – chathura Aug 13 '13 at 07:48
  • @chathura2020: No, that's completely separate. That's to help avoid errors. Don't forget that you get a different set of variables every time a method is called. Methods aren't "initialized" when an object is created because there's nothing *to* initialize. – Jon Skeet Aug 13 '13 at 07:56
3

Method overriding happens whether or not the derived class has been initialized.

This is why you should avoid calling virtual methods in initializers.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964