aspose file tools*
The moose likes Beginning Java and the fly likes Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Java » Beginning Java
Bookmark ""Can Watch ""Can New topic
Author

"Can't reference a class variable before supertype constructor has been called !! "

Jean Fore
Ranch Hand

Joined: Feb 23, 2006
Posts: 33
Hi, I have question about a compile time error I am getting. I have 2 classes and one is extending the other one.
My problem is about the class variables are not getting recognized before I use the "this()" call in a constructor. Can anybody just go through the following?

public class MyClass extends MySuperclass{
int p,q;
public MyClass()
{
this(p,q); //ERROR is showing here..
p=9; // but NO ERROR here, that means 'p' is
//already declared.
}
public MyClass(int p, int q)
{
super(p,q);
this.p = p;
this.q = q;
}
}

class MySuperclass
{
static int x,y; // if the variable are static, no error
public MySuperclass()
{
this(x,y); // no ERROR since x and y are static
}
public MySuperclass(int x, int y)
{
super();
this.x=x;
this.y=y;
}
}



Thank you in advance
JEAN
[ March 22, 2006: Message edited by: Jean Fore ]
Jeff Albertson
Ranch Hand

Joined: Sep 16, 2005
Posts: 1780
What is your goal? Are you trying to do something specific or are you just probing the dark corners of the language definition?


There is no emoticon for what I am feeling!
Jean Fore
Ranch Hand

Joined: Feb 23, 2006
Posts: 33
Actually I am not doing anything specific. I just want to know if a class variable can be used in the constructor of a subclass when that constructor use the this() call to another constructor. I am reading the Khalid Mugal book and was slightly confused about the this(), super() calls in a constructor and wanted to make sure that I understand things. So I was trying small programs.
Could you please help me with this?
-JEAN
[ March 22, 2006: Message edited by: Jean Fore ]
Jeff Albertson
Ranch Hand

Joined: Sep 16, 2005
Posts: 1780
As far as I understand it, you can't do that.
Rusty Shackleford
Ranch Hand

Joined: Jan 03, 2006
Posts: 490
Originally posted by Jean Fore:


public class MyClass extends MySuperclass{
int p,q;
public MyClass()
{
this(p,q); //ERROR is showing here.. The error is actually in the super class constructor, the reported error line is not always accurate. The reason for the error is that p&q have no values at this point
p=9; // but NO ERROR here, that means 'p' is
//already declared. Yes it is already declared, 4 lines up
}
public MyClass(int p, int q)
{
super(p,q);
this.p = p;
this.q = q;
}
}

class MySuperclass
{
static int x,y; // if the variable are static, no error
public MySuperclass()
{
this(x,y); // no ERROR since x and y are static
}
public MySuperclass(int x, int y)
{
super(); //This is not required since the compiler takes care of the call to Object, not an error though
this.x=x; //this is where the errors really are, you are tring to set nothing into x and y
this.y=y;
}
}



Thank you in advance
JEAN

[ March 22, 2006: Message edited by: Jean Fore ]

[ March 22, 2006: Message edited by: Rusty Shackleford ]

"Computer science is no more about computers than astronomy is about telescopes" - Edsger Dijkstra
Jean Fore
Ranch Hand

Joined: Feb 23, 2006
Posts: 33
Thank you so much Rusty! I went and debugged my program step by step since you told me that those variables do not have any values initially. And I saw that they are getting the values only at the end. So it made me believe that all the instance variable are getting initialized only after the constructor of a class and it's super classes in the inferitance hierarchy are called. Am I right?
-JEAN
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
I disagree. The error occurs right where it says it does. See the JLS:


Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:

1. Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
2. If this constructor begins with an explicit constructor invocation of another constructor in the same class (using this), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 5.
3. This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step 4.
4. Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5. (In some early implementations, the compiler incorrectly omitted the code to initialize a field if the field initializer expression was a constant expression whose value was equal to the default initialization value for its type.)
5. Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.


Note that the invocation of the superclass constructor occurs before instance initializers and instance variable initializers. At the point in which you are trying to pass them they are not initialized*. Even were you to assign to them rather than simply declare them it wouldn't work.

* Technically, I believe the memory has been allocated and the variables initialized to their default values, but for whatever reason you're not allowed to use them.
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
From the JLS again:

An explicit constructor invocation statement in a constructor body may not refer to any instance variables or instance methods declared in this class or any superclass, or use this or super in any expression; otherwise, a compile-time error occurs.


I still don't see any explanation of why. If the variables are already allocated and initialized to their default values then in theory you'd think it'd be useable. I can see why this would be undesirable, however, as you would be observing the variable before the variable intializer is executed.
Rusty Shackleford
Ranch Hand

Joined: Jan 03, 2006
Posts: 490
They are not initialized. The super constructor is always the first thing called, whether it is explicitly or implicitly called. So the class level variable may be delared but are not initialized with the default values, so the compiler is complaining. This may not be 100% technically correct, but in reality, it is what is happening.
[ March 22, 2006: Message edited by: Rusty Shackleford ]
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
The JLS says otherwise.


In the example:

class Point {
int x, y;
Point() { x = 1; y = 1; }
}
class ColoredPoint extends Point {
int color = 0xFF00FF;
}
class Test {
public static void main(String[] args) {
ColoredPoint cp = new ColoredPoint();
System.out.println(cp.color);
}
}

a new instance of ColoredPoint is created. First, space is allocated for the new ColoredPoint, to hold the fields x, y, and color. All these fields are then initialized to their default values (in this case, 0 for each field). Next, the ColoredPoint constructor with no arguments is first invoked. Since ColoredPoint declares no constructors, a default constructor of the form:

ColoredPoint() { super(); }

is provided for it automatically by the Java compiler.

This constructor then invokes the Point constructor with no arguments. The Point constructor does not begin with an invocation of a constructor, so the compiler provides an implicit invocation of its superclass constructor of no arguments, as though it had been written:

Point() { super(); x = 1; y = 1; }

Therefore, the constructor for Object which takes no arguments is invoked.


The memory is allocated and the variables have their default value. However, the JLS specifically says that using them in an explicit constructor invocation is a compile-time error.

EDIT: In fact, this not only happens before the superclass constructor is invoked but before ANY constructor is actually invoked.
[ March 22, 2006: Message edited by: Ken Blair ]
sandeep.ksharma
Greenhorn

Joined: Mar 22, 2006
Posts: 1
Hey Jean I think u r little bit confused about the working of super and this.

About working of super and this--- super is used (by the sub class) to invoke the constructor of super class and to access members of super class whereas this is used to refer the current object and also to invoke the constructor.

In the code there is compile time error when "this" with instance variables as arguments is called in the constructor of derived class.its because we have no reference to instance variables before the creation of object of a class,thats why we cant pass instance variables as arguments before the object is created.but we can pass class variable(variables with static keyword)as a argument in the "this" method because memory is allocated to class variables during the loading of class (ie. we have a reference).thats why there is no error when "this" with class variables as arguments is called in the super class.

hope this will help you.thank you for reading this.
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
Originally posted by sandeep.ksharma:
In the code there is compile time error when "this" with instance variables as arguments is called in the constructor of derived class.its because we have no reference to instance variables before the creation of object of a class,thats why we cant pass instance variables as arguments before the object is created.


The instance variables are already allocated and initialized to their default values according to the JLS. By the time a constructor is invoked the instance is already 'created', rather it just hasn't been 'initialized'.

but we can pass class variable(variables with static keyword)as a argument in the "this" method because memory is allocated to class variables during the loading of class (ie. we have a reference).thats why there is no error when "this" with class variables as arguments is called in the super class.


A class is not necessarily initialized at the same time it is loaded. The reason you can use a static variable is because the variable belongs to the class and by the time a constructor is ever invoked the class has been loaded and initialized.
Tony Morris
Ranch Hand

Joined: Sep 24, 2003
Posts: 1608
Originally posted by Rusty Shackleford:
They are not initialized. The super constructor is always the first thing called, whether it is explicitly or implicitly called. So the class level variable may be delared but are not initialized with the default values, so the compiler is complaining. This may not be 100% technically correct, but in reality, it is what is happening.

[ March 22, 2006: Message edited by: Rusty Shackleford ]


For those who are unsure or may be potentially misled, the above is untrue (or at the very least, an obfuscation of reality).
The JLS (in this case) is authoritative and correct - assuming a common interpretation, of which you can be pretty safe in this case.

Related fun: http://jqa.tmorris.net/GetQAndA.action?qids=10&showAnswers=true


Tony Morris
Java Q&A (FAQ, Trivia)
Jean Fore
Ranch Hand

Joined: Feb 23, 2006
Posts: 33
Thank you everyone who participated in this discussion and especially for doing reasearch in JLS! I feel like I have got lot more knowledge about this concept after reading your answers and doing some research in that. Thank you everone again I realy appreciate your help
JEAN
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

Originally posted by Ken Blair:

I still don't see any explanation of why. If the variables are already allocated and initialized to their default values then in theory you'd think it'd be useable. I can see why this would be undesirable, however, as you would be observing the variable before the variable intializer is executed.


They actually are observable in their uninitialized state! Imagine that this class we're talking about has a polymorphic method, and the subclass implementation accesses subclass variables -- say, it prints them to System.out, just for fun. Then if the superclass constructor calls this polymorphic method, the child's implementation will be invoked, and you'll see the default-initialized (i.e., pre-child-constructor) values of the child's member variables!

Calling a non-final method from a constructor is considered by many to be a Bad Practice because of this possibility -- or more generally, because the child object isn't fully constructed when its method is invoked.


[Jess in Action][AskingGoodQuestions]
Jeff Albertson
Ranch Hand

Joined: Sep 16, 2005
Posts: 1780
Originally posted by Ernest Friedman-Hill:

Calling a non-final method from a constructor is considered by many to be a Bad Practice because of this possibility -- or more generally, because the child object isn't fully constructed when its method is invoked.


By way of comparison, C++ behaves differently from Java. Suppose Dog extends Animal and Animal's constructor calls polymorphic method growHead. In Java, when constructing a Dog, Dog's growHead would be called, while in C++, even though growHead is virtual, Animal's growHead will be called. The fact that Java/C++ disagree on what to do indicates to me that one may have wandered out of the OOP standard practices.
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

C++'s system is called "type evolution" and it's complicated and confusing in its own right. The type evolution rules are part of what makes implementing C++ multiple inheritance such a bear. The Java folks quite deliberately decided to do something much simpler; it has its own problems, of course, but at least they're easy to understand.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
[EFH]: They actually are observable in their uninitialized state!

By "uninitialized", you mean the variable has been initialized to its default value (null, 0, or false), but it hasn't been set to that value the programmer wants to initialize to, because the relevant instance initializer, instance variable initializer, or constructor body have not run yet. Right? I have the feeling several of the apparent disagreements in the preceding paragraphs are because "initialized" can mean either initialized-to-default or initialized-by-initializer, depending on who the author is. Too bad there hasn't been an unambiguous definition provided for this term, as it would probably help clear things up.


"I'm not back." - Bill Harding, Twister
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24187
    
  34

Originally posted by Jim Yingst:
[b][
By "uninitialized", you mean the variable has been initialized to its default value (null, 0, or false), but it hasn't been set to that value the programmer wants to initialize to, because the relevant instance initializer, instance variable initializer, or constructor body have not run yet. Right?


Yep.

My assumption has always been (based not on inspection of the source, but on how I would do it myself) is that the default initialization happens automatically because the allocator effectively calls "calloc" -- i.e., zeros out the block of memory that's allocated for an object. The members aren't initialized one by one.
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
Originally posted by Ernest Friedman-Hill:
They actually are observable in their uninitialized state! Imagine that this class we're talking about has a polymorphic method, and the subclass implementation accesses subclass variables -- say, it prints them to System.out, just for fun. Then if the superclass constructor calls this polymorphic method, the child's implementation will be invoked, and you'll see the default-initialized (i.e., pre-child-constructor) values of the child's member variables!

Calling a non-final method from a constructor is considered by many to be a Bad Practice because of this possibility -- or more generally, because the child object isn't fully constructed when its method is invoked.


I know, in fact prior to the 3rd ed. you could even see final variables that were definitely assigned in an inconsistent state in an anonymous inner class since the copy happened after initialization of the instance. I'm just wondering why the JLS has that specific rule about it in explicit constructor invocations. The only thing I can come up with is that it would mislead developers into thinking the variable initializers had been executed, but that's just a guess.
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
Originally posted by Jim Yingst:
By "uninitialized", you mean the variable has been initialized to its default value (null, 0, or false), but it hasn't been set to that value the programmer wants to initialize to, because the relevant instance initializer, instance variable initializer, or constructor body have not run yet. Right? I have the feeling several of the apparent disagreements in the preceding paragraphs are because "initialized" can mean either initialized-to-default or initialized-by-initializer, depending on who the author is. Too bad there hasn't been an unambiguous definition provided for this term, as it would probably help clear things up.


I personally think it'd just be easier to refer to the first as 'allocation' and the second as 'initialization'. Or perhaps the first as 'initialization' and the second as 'assignment'. The terminology is certainly a bit murky, but I don't think that's the source of confusion. I think the confusion is two fold. First, the OP is/was unaware that the instance variables they were trying to pass in an explicit constructor hadn't been assigned values yet, that the initialization of the subclass including instance initializers and instance variable initializers occurs after the superclass, not before. Second, there is/was the misconception that the explicit/implicit superclass constructor invocation happened before memory allocation. It doesn't, and as we all (hopefully) know Java doesn't allocate memory without 'intializing' it to some default value for security reasons.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: "Can't reference a class variable before supertype constructor has been called !! "