• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Calling overridden methods from a constructor

 
Andrew Keidel
Greenhorn
Posts: 27
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Howdy!
I think this question is an interesting one.
Imagine this situation:
1. We have a class Base with public method makeReady().
2. Base calls makeReady() from within its constructor.
3. We make a class Derived that extends Base and overrides the makeReady() method.
My question is this: What happens when we try: "Derived d = new Derived();"? More specifically, when the constructor in Derived calls Base's constructor (which is always done because Base is its parent class), Base's constructor calls the makeReady() method... who's makeReady() method does it call?
If you think the answer is obviously that in this case, Derived's makeReady() method is called by Base's constructor, you may be right about the answer (I'm not sure), but you're wrong that it's obvious. In C++, the above scenario does NOT work this way. Instead, in C++, when Base's constructor is called through Derived's constructor, the virtual makeReady() method call in Base's constructor will use Base's own makeReady() method.
I don't understand why this happens in C++, and I don't know what happens in Java. It's easy enough to test this out with code, but what I'm more curious about is the REASON why each language works the way it does.
Here is a link to the C++ explanation, which I don't fully understand:
http://www.research.att.com/~bs/bs_faq2.html#vcall
Help, please! Thanks!
 
Manfred Leonhardt
Ranch Hand
Posts: 1492
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Andrew,
Ditto for java ... works exactly as explained in the article.
OBVIOUS: base called before derived is created therefore no derived class to override called method!
Regards,
Manfred.
 
Cindy Glass
"The Hood"
Sheriff
Posts: 8521
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
So the question is - at the point when the makeReady() method is called - is the thing calling the method a Base or a Derived?
During Construction the JVM walks up the constructor chain to the highest point and then proceeds to construct each class on the way down.
So first the JVM creates an Object instance (no brainer), then it constructs the Base stuff. It is during this activity that the method makeReady() is called. So it is a Base that is calling the method - the Base version is used. After this the Derived constructor is finally added to the party. If the Derived constructor were to also make a call to the makeReady() method, then it would be overridden and that time the Derived version would be used.
Of course if you make such a call from OUTSIDE the class constructors (a more typical use), as in:
Base b = new Derived();
b.makeReady(); //uses the Derived version
it is easier to see that it is a Derived object that is making the method call, so the Derived version is used.
 
Irene Loos
Ranch Hand
Posts: 78
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Andrew,
You may greatly benefit from "How my Dog learned Polymorphism" article on http://www.javaranch.com/campfire.jsp. It also talks about differences beetwen Java and C++.
Irene
 
Geoffrey Falk
Ranch Hand
Posts: 171
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Nice explanation, but according to my experiment with jdk1.3.1, it is wrong. The Derived method gets called in both cases. What is the logic behind that?
It is a bad idea to call non-final or non-private methods from a constructor. Enlightenment is found here:
http://mindprod.com/gotchas.html#CONSTRUCTORINIT
Geoffrey
[ May 04, 2002: Message edited by: Geoffrey Falk ]
[ May 04, 2002: Message edited by: Geoffrey Falk ]
 
Andrew Keidel
Greenhorn
Posts: 27
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks, Geoffrey!
So, Manfred and Cindy, it seems that you are both mistaken. Indeed, the method of the derived class is called from the constructor of the base class!
Manfred, you should not state something as "OBVIOUS" unless it is both obvious *and* correct.
Below is sample code for proving that Java works as Geoffrey and I fear. I am still hoping that someone can explain this question: *WHY* DOES JAVA WORK THIS WAY? Manfred, I believe that Java perhaps ought to work the way you describe, and the way C++ works, but apparently it does not. And the article Geoffrey points out highlights the problems that can result from this peculiarity of the Java language.
SAMPLE CODE:
class Base {
Base() {
doIt();
}
public void doIt() {
System.out.println("BASE");
}
}
public class Derived extends Base {
public void doIt() {
System.out.println("DERIVED");
}
public static void main(String args[]) {
Derived d = new Derived();
}
}
 
Geoffrey Falk
Ranch Hand
Posts: 171
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think the compiler ought to give a warning or an error, if you try to call a non-final and non-private method from a constructor. This would avoid all such problems.
[ May 04, 2002: Message edited by: Geoffrey Falk ]
 
Dirk Schreckmann
Sheriff
Posts: 7023
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Andrew & Geoffrey,
You are mistaken.
 
Dirk Schreckmann
Sheriff
Posts: 7023
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Consider:
 
Andrew Keidel
Greenhorn
Posts: 27
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Dirk,
We are not mistaken.
The code you've provided is exactly my point. Sure, constructing a new Base works as we'd expect. The question was whether constructing a new Derived uses the doIt() method from Base or from Derived.
The initial explanations given in this thread said "new Derived()" used the doIt() method from Base. That is incorrect. In fact, it uses the doIt() method from Derived. The problem here is that if Derived has its own member variables that get initialized in its constructor and that are used by its doIt() method, we will be calling a method that incorrectly assumes it is using initialized variables.
 
Andrew Keidel
Greenhorn
Posts: 27
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
An explicit example of the problem being discussed is given below. Compiling and running this will give a runtime error (NullPointerException).

class Base {
Base() {
doIt();
}
public void doIt() {
System.out.println("BASE");
}
}
public class Derived extends Base {
public Integer myInt;
public Derived() {
super();
myInt = new Integer(77);
}
public void doIt() {
System.out.println("DERIVED");
System.out.println(myInt.toString());
}
public static void main(String args[]) {
Derived d = new Derived();
}
}
 
Dirk Schreckmann
Sheriff
Posts: 7023
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You know what, I read Cindy's post too quickly, and so the rest of the posts were viewed in the wrong light. My previous assertion of the mistaken parties was itself mistaken.
 
Andrew Keidel
Greenhorn
Posts: 27
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
One more thing... Manfred and Cindy, sorry if I sounded rude before. I do greatly appreciate your input. I think I got a little surprised by the explanations and especially the use of the word "obvious." That's all.
Cheers,
Andy
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My previous assertion of the mistaken parties was itself mistaken.
"We apologise again for the fault in the subtitles. Those responsible fot sacking the people who jave just been sacked, have been sacked."
I think the compiler ought to give a warning or an error, if you try to call a non-final and non-private method from a constructor. This would avoid all such problems.
Agreed. A warning at least would be appropriate, since it can easily lead to confusion.
Here's another demonstration for those who aren't sure what's going on:

This has output:

Note that when the Base constructor is called from within the Sub constructor, "this" clearly refers to an instance of Sub, not Base. Even though "this" has not been completely constructed yet, the JVM knows what class it will ultimately be. This is how it's able call overriding methods from the constructor - for better or worse.
 
Cindy Glass
"The Hood"
Sheriff
Posts: 8521
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Jim Yingst:
Note that when the Base constructor is called from within the Sub constructor, "this" clearly refers to an instance of Sub, not Base. Even though "this" has not been completely constructed yet, the JVM knows what class it will ultimately be. This is how it's able call overriding methods from the constructor - for better or worse.


Duh :roll: Thank you for straightening us out Jim. < sheesh Cindy >
 
Thomas Paul
mister krabs
Ranch Hand
Posts: 13974
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This is very bad behavior on the part of Java. And there is really no way to change it because it would effect too many programs already written.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic