constructor weirdness - Java bug or as intended?

Notice that the two "dumps" happen one right after another--one as the very last thing the constructor does, and the other one as the first call after the constructor. Yet b goes back to being 0...

-

public class A

{

public int a = 0;

public A()

{

init();

}

public void init()

{

a = 1;

}

}

-

public class B extends A

{

public int b = 0;

public B()

{

super();

}

public void init()

{

super.init();

b = 1;

System.out.println("DUMPING FROM B.INIT:");

dump();

}

public void dump()

{

System.out.println("B:");

System.out.println(a);

System.out.println(b);

}

}

--

...

B myB = new B();

myB.dump();

...

And the output is:

DUMPING FROM B.INIT:

B:

1

1

B:

1

0

[942 byte] By [TheWorldIsAHashMapa] at [2007-11-26 16:07:45]
# 1

I think the issue here is that method overriding always looks for the method lowest in the chain of inheritance first. When init() is called from your parent class, the init() method is available to be called in both the parent and child class and, based on the rules of method overriding, the child's init() method will be called.

dfg59a at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 2
Yes, and the println from B::init shows that it is being called, which is why we get the first dump with both values set to 1. The question is why does the value of B.b revert back to 0 after that (second dump)?
TheWorldIsAHashMapa at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 3
This code is confusing to me...how is the second call to dump being made without printing "DUMP FROM blah blah"?
dfg59a at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 4

Just below the public int b= 0; line add the following block:{ System.out.println("b= 0"); }

and see what happens. Your super class object assumes the existence

of the subclass object which is still in statu nascendi.

kind regards,

Jos

JosAHa at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 5
The "DUMPING FROM ..." is just a println in B::init(), it's not part of dump() itself.
TheWorldIsAHashMapa at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 6

JosAH -- thanks, you're absolutely right! If I declare b as public int b; (without = 0), the second dump prints out two 1s. So I guess the answer is that members get allocated before the constructor (makes sense) but any inline initialization takes place AFTER the constructor is called. Which is still weird. I mean, if I didn't have any inheritance and it was a single class where an integer member was set to 0 inline and then in the constructor was set to 1, I'd expect it to stay 1 when the object is constructed. In this case, it looks like because of the inheritance, the inline init happens after the constructor.

TheWorldIsAHashMapa at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 7

> JosAH -- thanks, you're absolutely right! If I declare b as public int b;

> (without = 0), the second dump prints out two 1s. So I guess the

> answer is that members get allocated before the constructor

> (makes sense) but any inline initialization takes place AFTER the

>constructor is called. Which is still weird.

Yes; the trick is that method overriding is available before the subclass

object has been initialized (very much unlike C++). Java instantiates

objects from the inside out, i.e. when the new operator is called,

the first thing that happens after the ctor is invoked, another ctor is invoked

or a superclass ctor is invoked. After that one returns the initialization

of the object is performed (as in public int b= 0).

When the superclass ctor is in control method overriding is valid already.

That's why you experienced that 'strange' behaviour because a

subclass method was called before that same subclass object was

even 'born' and that subclass's initialization block had a chance to execute.

kind regards,

Jos

JosAHa at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 8

> JosAH -- thanks, you're absolutely right! If I

> declare b as public int b; (without = 0), the second

> dump prints out two 1s. So I guess the answer is

> that members get allocated before the constructor

> (makes sense) but any inline initialization takes

> place AFTER the constructor is called. Which is

> still weird. I mean, if I didn't have any

> inheritance and it was a single class where an

> integer member was set to 0 inline and then in the

> constructor was set to 1, I'd expect it to stay 1

> when the object is constructed. In this case, it

> looks like because of the inheritance, the inline

> init happens after the constructor.

The complete sequence is [url http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.5]here[/url].

jverda at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 9

> JosAH -- thanks, you're absolutely right! If I

> declare b as public int b; (without = 0), the second

> dump prints out two 1s. So I guess the answer is

> that members get allocated before the constructor

> (makes sense) but any inline initialization takes

> place AFTER the constructor is called.

Not quite.

Parent's initializers ("inline initialization")

Parent's constructor

Child's intializers

Child's constructor

With other stuff interleaved as per the link to the JLS in my last post.

jverda at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 10
> The complete sequence is [url http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.5]here[/url].I like the way you did that--you can actually tell that it's a link the way you did it. :)
doremifasollatidoa at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 11

> > The complete sequence is [url http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.5]here[/url].

>

> I like the way you did that--you can actually tell

> that it's a link the way you did it. :)

Yeah, unless you take fairly extraordinary measures, it can be hard to spot links in these forums. Lovely bloody colors. :rolleyes:

jverda at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 12
> The complete sequence is here.It's a lie. That misses out assignment to this$0 (and similar) variables, which occurs before the call to the super-constructor in Java 1.4 and later.
YAT_Archivista at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 13

> > The complete sequence is here.

>

> It's a lie. That misses out assignment to this$0 (and

> similar) variables, which occurs before the

> call to the super-constructor in Java 1.4 and later.

Eh? this$0? Is that a secret member variable that seeds this when a method or constructor is entered? Since this$0 doesn't exist as far as the programmer is concerned, I'd say it's irrelevant, but maybe I'm mising something. Care to elaborate?

jverda at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 14

> > The complete sequence is here.

>

> It's a lie. That misses out assignment to this$0 (and

> similar) variables, which occurs before the

> call to the super-constructor in Java 1.4 and later.

Are you talking about local variables that don't even belong to the object being created and are copied behind the scenes? Is that not an implementation detail, or perhaps an attribute of the memory model rather than object creation.

kablaira at 2007-7-8 22:30:04 > top of Java-index,Java Essentials,Java Programming...
# 15

> Eh? this$0? Is that a secret member variable that seeds

> this when a method or constructor is entered?

It's the link from a non-static inner class to its containing instance. public class Foo

{

public class Bar

{

}

}

generates Foo$Bar.class which javap's to public class Foo$Bar extends java.lang.Object{

final Foo this$0;

public Foo$Bar(Foo);

Code:

0:aload_0

1:aload_1

2:putfield#1; //Field this$0:LFoo;

5:aload_0

6:invokespecial#2; //Method java/lang/Object."<init>":()V

9:return

}

For anyone who can't read bytecode, that means public Foo$Bar(Foo foo)

{

this.this$0=foo;

super();

}

If I recompile with -source 1.3 -target 1.3 then I get public class Foo$Bar extends java.lang.Object{

private final Foo this$0;

public Foo$Bar(Foo);

Code:

0:aload_0

1:invokespecial#1; //Method java/lang/Object."<init>":()V

4:aload_0

5:aload_1

6:putfield#2; //Field this$0:LFoo;

9:return

} instead.

This was changed in 1.4 because it led to a lot of confusing NPEs when the super-constructor called overridden methods which tried to access the enclosing instance of the outer class - particularly an issue for Swing developers, because they tend to use a lot of inner classes.

YAT_Archivista at 2007-7-21 16:39:54 > top of Java-index,Java Essentials,Java Programming...