Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Overwritten method has no access to local variable if it contains field data

Reply
Thread Tools

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

 
 
Daniel
Guest
Posts: n/a
 
      07-21-2004
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
 
Reply With Quote
 
 
 
 
David Hilsee
Guest
Posts: n/a
 
      07-22-2004
"Daniel" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) om...
> 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.

--
David Hilsee


 
Reply With Quote
 
 
 
 
David Hilsee
Guest
Posts: n/a
 
      07-22-2004

"David Hilsee" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> > 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");


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.

--
David Hilsee


 
Reply With Quote
 
Daniel
Guest
Posts: n/a
 
      07-22-2004
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
 
Reply With Quote
 
Daniel
Guest
Posts: n/a
 
      07-22-2004
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
 
Reply With Quote
 
Chris Uppal
Guest
Posts: n/a
 
      07-22-2004
Daniel wrote:

> 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


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
javascript validation for a not required field, field is onlyrequired if another field has a value jr Javascript 3 07-08-2010 10:33 AM
Block binding does not contains local variable Artem Voroztsov Ruby 2 04-20-2008 07:32 AM
How do I scope a variable if the variable name contains a variable? David Filmer Perl Misc 19 05-21-2004 03:55 PM
Regex problem, match if line contains <a>, unless it also contains <b> James Dyer Perl 5 02-20-2004 12:29 PM
a static local variable in a static method is thread local storage? Patrick Hoffmann C++ 3 08-08-2003 02:37 PM



Advertisments