Initialization & Inheritance

  • Thread starter Christian Pontesegger
  • Start date
C

Christian Pontesegger

Hi all,

for a recent project I was trying to initialize members of a derived
class from the constructor of the super class (done using an abstract
method). This is an example code:

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

protected abstract void init();
}

public class Derived extends Base {

private int foo = 0;

public Derived() {
super();
}

protected void init() {
foo = 5;
}

public static void main(String[] argv) {
System.out.println((new Derived()).foo);
}
}


Running this example will print "0". As I understand it Base calls
Derived.init, which sets the value to 5. Afterwards the constructor of
Derived is called and foo is reinitialized. This seems strange to me. I
expected either initialization of all members done before any
constructor is called or an error when trying to access a member which
isn't properly initialized.

Now I know how to get my intended behavior, just don't initialize foo =
"0" and this program will return "5" as expected (at least by me).

But is this behavior mentioned above a design problem or is it even
useful and I can't see the meaning of it?

thanks
Christian Pontesegger
 
E

Eric Sosman

Christian Pontesegger wrote On 05/19/06 17:19,:
Hi all,

for a recent project I was trying to initialize members of a derived
class from the constructor of the super class (done using an abstract
method). This is an example code:

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

protected abstract void init();
}

public class Derived extends Base {

private int foo = 0;

public Derived() {
super();
}

protected void init() {
foo = 5;
}

public static void main(String[] argv) {
System.out.println((new Derived()).foo);
}
}


Running this example will print "0". As I understand it Base calls
Derived.init, which sets the value to 5. Afterwards the constructor of
Derived is called and foo is reinitialized. This seems strange to me. I
expected either initialization of all members done before any
constructor is called or an error when trying to access a member which
isn't properly initialized.

Initializing all members before calling the constructor
is a non-starter. Conceptually, all those initializations
are magically inserted at the start of every constructor in
the class -- indeed, if you disassemble the byte code for a
class with just one constructor, you'll see that the compiler
does exactly that. Member initialization is part of instance
construction.

Detecting non-initialization at run time would require a
way of tagging the uninitialized data, and maintaining and
testing the tag on each access. That sort of thing would be
pretty expensive[*] -- and besides, it wouldn't change the
behavior of your example! Your problem isn't failure to
initialize, but double initialization.

[*] I recall a long-ago system that managed to do this.
All variable references were indirect through a symbol table
that contained a pointer to the actual memory location where
the data lived. As initialized, all the pointers aimed one
byte too high; if you used the pointer as it stood, you'd get
a bad-alignment trap from the hardware. But when a variable
was written, the code first cleared the low-order bit of the
pointer in the table, so all subsequent references found a
properly-aligned pointer. This was probably the cheapest
uninitialized-variable catcher I've ever seen, yet it doubled
the cost of every read and tripled the cost of every write.
Now I know how to get my intended behavior, just don't initialize foo =
"0" and this program will return "5" as expected (at least by me).

But is this behavior mentioned above a design problem or is it even
useful and I can't see the meaning of it?

The "design problem," I think, is the double initialization
of foo. If you want to initialize it at the point of declaration
then go ahead and do so -- but don't turn around and re-initialize
it in init(). If you want to rely on init(), don't initialize in
the declaration. Choose one way or the other but not both.

Another way to view things is to note that you've violated
one of the Big Rules: Never let a constructor call an overridable
method on the object being constructed. The reason for the
prohibition is to avoid exactly the sort of situation you've run
into here, where an overriding method gets its hands on an
incompletely initialized object.
 
T

Tony Morris

Christian Pontesegger said:
Hi all,

for a recent project I was trying to initialize members of a derived
class from the constructor of the super class (done using an abstract
method). This is an example code:

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

protected abstract void init();
}

public class Derived extends Base {

private int foo = 0;

public Derived() {
super();
}

protected void init() {
foo = 5;
}

public static void main(String[] argv) {
System.out.println((new Derived()).foo);
}
}


Running this example will print "0". As I understand it Base calls
Derived.init, which sets the value to 5. Afterwards the constructor of
Derived is called and foo is reinitialized. This seems strange to me. I
expected either initialization of all members done before any
constructor is called or an error when trying to access a member which
isn't properly initialized.

Now I know how to get my intended behavior, just don't initialize foo =
"0" and this program will return "5" as expected (at least by me).

But is this behavior mentioned above a design problem or is it even
useful and I can't see the meaning of it?

thanks
Christian Pontesegger

Here is another example that demonstrates your observation:
http://jqa.tmorris.net/GetQAndA.action?qids=10&showAnswers=true
You are simply observing one of the many flaws of behaviour inheritance -
which implies some knowledge about the future.
http://contractualj.com/ "All classes are declared final. Concrete behaviour
inheritance is not permitted."
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,241
Latest member
Lisa1997

Latest Threads

Top