• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Selection of invocation of overridden method during constructor chaining

 
Ranch Hand
Posts: 100
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hey people,

I don't understand, why when in the constructor of the superclass A the method init() is called (line 4), the overridden version of the subclass is invoked (line 26) and not the superclass version (line 7):



I would have guessed that above code prints

test
1


But instead you get a NPE (because when the constructor of B is invoked

then there is first the implicit call to super:

which is the constructor of A:

but here now this init() method is not the version of A () but the overriden version of the subclass (B): ... which throws an NPE of course, because the initialization of s has not occured yet (it happens only after the implicit call to super() has finished (see ))

Does anyone know why this happens?

Thanks in advance...
 
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Bora Sabrioglu wrote:Does anyone know why this happens?


I don't understand the question. You've just given a perfect explanation of it yourself. The class being created is a B, therefore any call to init() will run B.init(), which exhibits exactly the behaviour you just described.

If you're asking "why did the architects do it that way?", my question to you would be: What else would you have it do?

Winston
 
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Note that you should probably never call overridable methods from a constructor, or pass this as an argument to methods.

If you need to call a method of the class being constructed, make that method private or final.
 
Bora Sabrioglu
Ranch Hand
Posts: 100
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Winston Gutkowski wrote:If you're asking "why did the architects do it that way?"...



Oh no, that's not what I meant. I asked the question, because I'm just a little clueless and confused, that's all.
I don't understand what seems very clear to you:

The class being created is a B, therefore any call to init() will run B.init(), which exhibits exactly the behaviour you just described.



So far I haven't read anything about this and that's why it's new to me. I (falsely) assumed, that because the init method is called inside the constructor of A and A has its own init method, that A.init() will be chosen.

If you have

and then somewhere you write then because the object is of type A , the A version of init() will be invoked. And if you have then now, because the object is of type B , the B version of init() will be invoked. (That's because of polymorphism.)

Does the same rule apply here in the initial constructor example as well (where you just construct an object of type B and don't assign that object to any reference and later in the superconstructor you invoke init() without any reference and the dot operator)? and
 
Marshal
Posts: 28193
95
Eclipse IDE Firefox Browser MySQL Database
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Bora Sabrioglu wrote:then now, because the object is of type B , the B version of init() will be invoked. (That's because of polymorphism.)



This is all you need to know. Whether the code which calls the init() method is in a constructor -- or a method -- declared in a superclass of B has nothing to do with it. It seems you assumed that constructors should work differently than methods as far as polymorphism is concerned, or perhaps you hadn't yet got to thinking about calls from a method, but they don't.
 
Bora Sabrioglu
Ranch Hand
Posts: 100
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Paul Clapham wrote:

Bora Sabrioglu wrote:then now, because the object is of type B , the B version of init() will be invoked. (That's because of polymorphism.)



This is all you need to know.



Good to know.

Here is another way that helps me understand this better:

Since Java implicitly inserts, when there is a call to a method without a reference (like init()), a this reference (so init() becomes implicitly this.init()) implicitly becomes

And since this always refers to the current object and the object is of type B (because of new B();) the B version of init() will be called.

Thank you guys for helping me debug myself
 
Java Cowboy
Posts: 16084
88
Android Scala IntelliJ IDE Spring Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I want to stress this important point that Stephan made:

Stephan van Hulst wrote:Note that you should probably never call overridable methods from a constructor, or pass this as an argument to methods.


The purpose of a constructor is to initialize a new object. If you are calling overridden methods from inside a constructor, then you are calling a method on an object that might not be fully initialized. That can lead to unexpected behaviour. For example: can you explain the output of the following program?

You should not let the 'this' reference escape outside of a constructor, because then there might be code outside of the constructor that gets exposed to an object that is not fully initialized. Besides the example above, there are other ways that you can get this kind of problem. For example by starting a thread inside the constructor that accesses the object's member variables.

 
Bora Sabrioglu
Ranch Hand
Posts: 100
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jesper de Jong wrote: For example: can you explain the output of the following program?


It prints null since instance variables are initialized AFTER all superclass constructors complete... and since the call to init was made from within the superclass constructor, the attribute 'message' still holds the default value... which is null (see p. 469 SCJP6 Study Guide Bates/Sierra for reference).
 
Marshal
Posts: 79180
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Bora Sabrioglu wrote: . . . It prints null . . .

Not when I tried it, it didn't.
 
Bora Sabrioglu
Ranch Hand
Posts: 100
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:Not when I tried it, it didn't.


Now it gets interesting...
 
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
HI Sabrioglu,

this is pretty simple, here we are doing inheritance, method overriding .
1) Class A init() method was Overridden by Class B int(),
2) The exact reason for getting Null pointer exception was Super class (Class A) constructor was calling sub class (Class B ) int() method.
public void init() {
System.out.println(s+=s.length());
}
At the time of executing class A constructor we didnt initialize variable S.


 
Bora Sabrioglu
Ranch Hand
Posts: 100
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

sreenivasarao mydukuri wrote:Super class (Class A) constructor was calling sub class (Class B ) int() method.


Yes. That was the point where I falsely assumed that the super class is calling its own init() method. Now I know better.
 
Bora Sabrioglu
Ranch Hand
Posts: 100
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:

Bora Sabrioglu wrote: . . . It prints null . . .

Not when I tried it, it didn't.


So what do you get as output? ...
 
Campbell Ritchie
Marshal
Posts: 79180
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Nothing. I got a NullPointerException instead.
 
sreenivasarao mydukuri
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:Nothing. I got a NullPointerException instead.



yes it will return null pointer exception because we are accessing string with out initialization......... it is correct.
 
Bora Sabrioglu
Ranch Hand
Posts: 100
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:Nothing. I got a NullPointerException instead.


Did you run the example of Jesper de Jong or the initial example in the first post of the OP (which is me)?
If you tried Jespers example and get an NPE then I really have no idea why this happens...
If you tried my example (the first post), then yes, as the previous poster correctly mentioned, the reason is trying to call the length() method on a String variable with the value 'null', since uninitialized.
 
Campbell Ritchie
Marshal
Posts: 79180
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Jesper's example. I was fully expecting it to print “null”.
 
Campbell Ritchie
Marshal
Posts: 79180
377
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I have tried it again and it printed “null”, which is what I expected earlier.
 
Bora Sabrioglu
Ranch Hand
Posts: 100
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
My state went from confused to (thought-that-)I-got-it back to confused again.

Stephan van Hulst wrote:If you need to call a method of the class being constructed, make that method private or final.


I did just that, the only difference to the initial example is in line 7, I just changed the modifier from public to private:

And now I don't understand, why the A.init() method is chosen over the B.init() method... :/
(now the program behaves EXACTLY the way I INITIALLY expected it to behave (that the A.init() method is invoked and not the B.init() version... that's why I opened this topic in the first place)

Now the B version clearly is not an overridden version of the A version, since class B doesn't even see the init() method of A (since is is marked private). So the B.init() is just a normal method of B that happens to have the same name as init() in A, but has no relationship to it whatsoever.

Am I right in assuming that the new insight that I had due to the posts above, that always the type of the object determines which version of a method is invoked (if object of type B, the B's init() is invoked) is only valid in the case of overriding? Or is this a wrong assumption?

And again, if you just implicitly insert a 'this.' in front of the call to init() in the A constructor, the current object is of type B, so why is not the B version invoked?
 
Campbell Ritchie
Marshal
Posts: 79180
377
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You need all the help you can get. For years programmers complained about little errors like trying to override the tostring() method and that it was not obvious why that didn't work. Then, in Java5, the @Override annotation was introduced which solves that problem. Add the @Override annotation to every method you think is an overriding method, and see what happens. You will need to recompile everything.
 
Campbell Ritchie
Marshal
Posts: 79180
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
While you work out the @Override annotation, I shall see whether I can work out why I got the Exception rather than null, which I expected. Maybe I copied your version, but I thought I had copied Jesper's version. One of those little mysteries of life. Since I overwrote the .java files, I have destroyed the evidence. So we shall never know. I must have copied something wrongly.
 
Bora Sabrioglu
Ranch Hand
Posts: 100
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:Add the @Override annotation to every method you think is an overriding method, and see what happens.


Ah, thanks for the hint... now I know what this Annotation is good for
I get:

error: method does not override or implement a method from a supertype


Since the superclass's init() was marked private, there was no way the subclass's init() could override the superclass's init(). I understand that.
What I DON'T understand is:

Why is now, when I mark A's init() as PRIVATE, A's init() invoked and not B's init()?

Since
implicitly becomes

with 'this' referring to an object of type B. That's why I would assume that B's init() is invoked, but it's not. A's init() is invoked... why does that happen if I mark A's init() as private?
(I think that I understood the case when it's marked public: then B's init() is overriding A's init(). And since the object being constructed is of type B ('this' refers to an object of type B) B's init() is invoked. But here in this case, when we mark A's init() as private something else is going on which leads to the invocation of A's init(). I would like to understand what that 'something' is.)
 
Campbell Ritchie
Marshal
Posts: 79180
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Because init in A is private, init in B cannot override it. The A constructor can only therefore call the A version.
 
Bora Sabrioglu
Ranch Hand
Posts: 100
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:Because init in A is private, init in B cannot override it.

Right.

Campbell Ritchie wrote: The A constructor can only therefore call the A version.

Okay... so it seems that the assumption that I made above was correct?

Am I right in assuming that the new insight that I had due to the posts above, that always the type of the object determines which version of a method is invoked (if object of type B, the B's init() is invoked) is only valid in the case of overriding? Or is this a wrong assumption?


And when I think about it in conclusion, what we were talking about all along was basically polymorphic method invocations... and these are known to work only with overridden methods. And since in the case of marking init private there is no overriding => there is no polymorphism, i.e. the decision of which method to call won't be made based on the type of the object anymore, or: init of the subclass (B) won't be called, since it is not overriding init of A.

p.102 SCJP6 Study Guide Bates / Sierra says: "Only overridden instance methods are dynamically invoked based on the real object's type."

I think that I finally got it
 
Campbell Ritchie
Marshal
Posts: 79180
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


When Jesper said only to call private or final methods from the constructor it was because they cannot be overridden to give unexpected behaviour.
 
reply
    Bookmark Topic Watch Topic
  • New Topic