Overwritten method has no access to local variable if it contains field data

D

Daniel

Hi

Did you know that an overwritten method has no access to local
variables containing a member field value when method is called from
the constructor?

Example: Running this

import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
public class TestBug {
private String datum = "Member-String";
public static void main(String[] args) {
new TestBug().new TestAction().actionPerformed(null);
}
private final class TestAction extends AbstractAction {
public void actionPerformed(final ActionEvent e) {
final String localString1 = TestBug.this.datum;
final String localString2 = "Local-String";
new Upper() {
protected void print(String cb) {
System.out.println(cb + ": " + localString1);
System.out.println(cb + ": " + localString2);
}
}.print("Method");
}
}
}
class Upper {
public Upper() {
print("Constructor");
}
protected void print(String calledBy) {
System.out.println("Upper-String");
}
}

Leads to

Constructor: null
Constructor: Local-String
Method: Member-String
Method: Local-String

The localString1 is not accessible from the constructor while
localString2 is. Do you know a workaround for it? Is it a bug?

Thanks
Daniel Frey
 
D

David Hilsee

Daniel said:
Hi

Did you know that an overwritten method has no access to local
variables containing a member field value when method is called from
the constructor?

Example: Running this

import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
public class TestBug {
private String datum = "Member-String";
public static void main(String[] args) {
new TestBug().new TestAction().actionPerformed(null);
}
private final class TestAction extends AbstractAction {
public void actionPerformed(final ActionEvent e) {
final String localString1 = TestBug.this.datum;
final String localString2 = "Local-String";
new Upper() {
protected void print(String cb) {
System.out.println(cb + ": " + localString1);
System.out.println(cb + ": " + localString2);
}
}.print("Method");
}
}
}
class Upper {
public Upper() {
print("Constructor");
}
protected void print(String calledBy) {
System.out.println("Upper-String");
}
}

Leads to

Constructor: null
Constructor: Local-String
Method: Member-String
Method: Local-String

The localString1 is not accessible from the constructor while
localString2 is. Do you know a workaround for it? Is it a bug?

A non-final method that is called from the constructor and is overridden
(not "overwritten") in the derived class will be bound to the derived
class's implementation, even though that derived class's constructor has not
yet been called. That means that the base object will call a method on an
derived object that is most likely not in a valid state. It is generally
considered bad form to do it because it can lead to unexpected behavior. If
I were to guess at what was happening, I'd say that the compiler handled the
strings differently because one was a constant, but I really can't say.
Someone who knows more of the nitpicky details might be able to tell you
what's going on. I avoid invoking derived class members from base class
constructors like the plague.
 
D

David Hilsee

To elaborate on what I said, I think that the above code was translated into
something equivalent to this:

final String localString1 = TestBug.this.datum;
final String localString2 = "Local-String";

class Derived extends Upper {
private final String member = null;
public Derived() {
member = localString1;
}

protected void print(String cb) {
System.out.println(cb + ": " + member);
System.out.println(cb + ": " + "Local-String");
}
}

new Derived().print("Method");

In the above code, calling print("Constructor") in Upper's constructor would
invoke Derived.print(String) before the Derived object's constructor had
run. Therefore, the value of the "member" is null.
 
D

Daniel

You're right, it is generally considered bad practice to invoke
non-final methods from a constructor. However, in this case, the
problem of overwriding methods used in the constructor takes some new
(and at least for me: yet unknown) dimensions.

Interestingly that in JDK 1.5 Beta 2 it seems to work:

Constructor: Member-String
Constructor: Local-String
Method: Member-String
Method: Local-String

Daniel Frey
 
D

Daniel

You're right, it is generally considered bad practice to invoke
non-final methods from a constructor. However, in this case, the
problem of overwriding methods used in the constructor takes some new
(and at least for me: yet unknown) dimensions.

Interestingly that in JDK 1.5 Beta 2 it seems to work:

Constructor: Member-String
Constructor: Local-String
Method: Member-String
Method: Local-String

Daniel Frey
 
C

Chris Uppal

Daniel said:
final String localString1 = TestBug.this.datum;
final String localString2 = "Local-String";

Besides the order-of-initialisation-in-constructors issues that have already
been discussed, the above declarations are much more different than they
appear.

The first declares String variable, marks it final, and generates code to
initialise it to the actual value of TestBug.this.datum at the time of
execution.

The second declares a String variable, marks it final, generates code to
initialise it to "Local-String", AND requires that the compiler repaces all
references to that variable with "Local-String". I.e. the compiler must not
generate code that actually uses the variable anywhere (normally -- you can
still get to it using reflection, JNI, or bytecodes not generated by javac).

(I have seen your post that says that 1.5 beta behaves differently. I don't
have time to investigate now, but I'm pretty confident in assuming some sort of
error -- in your test, in the beta compiler, or possibly in my own
understanding ;-)

-- chris
 

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,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top