• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

forward reference ?

 
Ranch Hand
Posts: 50
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The following piece of code gives an output of 0. Why is this ? Why isn't the output 10. When is the instance variable declared and when is it initialized. Isn't it being initialized here at the point of declaration ? Why isn't the matter of illegal forward reference coming up here since at the declaration of i we call the method which returns j which hasn't been declared yet ?? Can someone please help clear my confusion. thanx
public class AQuestion
{
private int i = giveMeJ();
private int j = 10;
private int giveMeJ()
{
return j;
}
public static void main(String args[])
{
System.out.println((new AQuestion()).i);
}
}
 
Ranch Hand
Posts: 301
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It looks like it is because of the ordering. If you switch the j line and put it above the x line, you will get 10. But since the i line is initialized before j is set to 10, you get 0 because 0 is the default value of an int (j).
Does that make sense?
 
Ranch Hand
Posts: 7729
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The int i, and int j are allocated and initialized to their default values 0 and 0 respectively. In computing the initial value of i giveMeJ() is called which picks up the value of j which is 0. Then j will be initialized to 10.
-Barry
 
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Exactly Nate. The code that initalizes the instance fields is gathered and placed inside the body of the constructor in "literal" order. That means that it will be executed in "order of appearance".
 
Ranch Hand
Posts: 1056
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Would this act differently if j had been declared final?
 
Jose Botella
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hey Ron you are right. It prints 10.
The reason is that compile constant expressions JLS 15.28 are not stored in the heap, within the image of the object as the instance fields are. Given that its value its known by the compiler, and it won't change; the compiler replaces each access to them in the code with the value itself. In this way avoids the time wasted accesing an instance field.
Look at the output of javap -c AQuestion , especifically the giveMeJ method when j is declared non final:

"aload_0" pushes into the operand stack the reference to the object on which giveMeJ was invoked. That is also known as "this".
"getfield #4" gets, from the object pointed to by the operand stack, the field especified by the constant pool entry number 4. It just happens to be j as javap shows. Then it pushes it into the operand stack.
"ireturn" returns the integer within the operand stack.
Because the instance fields that are variables are initaliazed, just after the creation of the object on the heap, by setting the memory to zero; that is the value that giveMeJ will return.
By the way, note that zero is the default initializing value for all primitives types, and also for the reference types -a.k.a. null for the later.
Look at the output when j is declared final:

As it was said above, the compiler has replaced an acces to j by the value of it.
"bipush 10" pushes into the operand stack 10.
[ August 17, 2002: Message edited by: Jose Botella ]
 
Ron Newman
Ranch Hand
Posts: 1056
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
However, here are a couple of interesting variations that seem to show that a "final" field may be anything but constant. On Java 1.1.8 these both print "0". Anyone want to try them on 1.4?
First example:

Second example:
 
Ron Newman
Ranch Hand
Posts: 1056
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
And yet another variation, this one not involving a blank final:

For me, it prints "0 10 10" .
 
Jose Botella
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This may be helpfull. from JLS 4.5.4


A variable can be declared final. A final variable may only be assigned to once. It is a compile time error if a final variable is assigned to unless it is definitely unassigned (�16) immediately prior to the assignment.
A blank final is a final variable whose declaration lacks an initializer.
Once a final variable has been assigned, it always contains the same value.


I also get the same results as you. JLS 15.28 exclude blank finals from compile constants expression. In fact the three examples spawn a field within the object in the heap.
[ August 17, 2002: Message edited by: Jose Botella ]
 
Barry Gaunt
Ranch Hand
Posts: 7729
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
'scuse me guys, does all that mean what I wrote up there was a load of bo***cks?
Ron, on the assumption that the variables are allocated and given the default values 0, and then the initializers run, and then the initialization blocks and finally the constructors all the results are predictable.
Or am I still missing summat?
- Barry
[ August 17, 2002: Message edited by: Barry Gaunt ]
 
Ron Newman
Ranch Hand
Posts: 1056
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Barry, I think you're 100% right except for the special case of final variables that are initialized to compile-time constants.
 
Barry Gaunt
Ranch Hand
Posts: 7729
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ron, do you mean the one with j=(int)Math.cos(0)*10 ? I do not think that that expression will be computed at compile time.
The same goes for the one with j=10; The constructor is the last (final) place in which a final variable can be initialized. However, in this case what is there to stop another constructor setting j=20; say?
I'll play a bit with some 1.4 code; tomorrow.
Cheers
 
Ron Newman
Ranch Hand
Posts: 1056
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
private final int j=(int)Math.cos(0)*10;
is definitely not a compile-time constant, but
private final int j=10;
is.
If either of these declarations appears in the class itself, it would be illegal for any constructor to assign a new value to j.
[ August 17, 2002: Message edited by: Ron Newman ]
[ August 17, 2002: Message edited by: Ron Newman ]
 
Barry Gaunt
Ranch Hand
Posts: 7729
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In the case of the member variable definition final int j = 10; doesn't compiler say "oh this is a constant, so I just replace j by 10 wherever it appears"? So instead of the variable getting the default value 0 in the first "memory allocate pass" it gets the constant (final) value of 10. Sort of...?
-Barry
PS:

Barry, I think you're 100% right except for


Ron, you are a born diplomat!
[ August 17, 2002: Message edited by: Barry Gaunt ]
 
Ranch Hand
Posts: 787
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Guys:
Seems like a very serious discussion is going on
here. I am new to Java so I may not catch on
as fast as you guys. May be one of you guys can
explain why following statement made by Ron, is
true:


private final int j=(int)Math.cos(0)*10;
is definitely not a compile-time constant, but
private final int j=10;


Why the first statement is not compile time constant?
Compiler can call that Math class method and
assign j's value. I would assume that j's value
would be run-time constant, if this statement
was placed in the constructor....
Thanks
Barkat
[ August 17, 2002: Message edited by: Barkat Mardhani ]
 
Barkat Mardhani
Ranch Hand
Posts: 787
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Guys:
I reread your notes few times. By phrase "compile
-time constant", you refer to value assigned in
the first pass. Now, I understand Ron's point.
Here is one more variation (to Ron's point):

It prints 0 10 10 instead of 10 10 10.
I guess anything
not assigned directly (i.e. with a deeper level
call), is NOT a compile time constant.
May be you already know this: If you make i a
static data member (in addition to final), all four variations in
compile time constant determination, are NO more
variation i.e. compiler will replace i with
its value in first pass. I tried it in 1.3.101 ver.
Thanks
Barkat
 
Jose Botella
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


Ron, on the assumption that the variables are allocated and given the default values 0, and then the initializers run, and then the initialization blocks and finally the constructors all the results are predictable.


Barry you are almost there.
It isn't like: first field initializers and then block initializers are run.
By using javap -c AClass is possible to see that the code initializing fields, and the code within block initializers is recollected by the compiler in textual order and placed within the body of the constructor. That is, if a block initializer appears before a field initializer, it will be executed first.
The compiler places this code just after the call to this(...) or super(...) within the constructor, but just before the code written by the programmer inside the constructor. Excecuting this constructor first the call to other constructor is runned. Then the initializer code for instance variables in textual order. And last, but not least, the code within the constructor.
 
Ron Newman
Ranch Hand
Posts: 1056
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
All initialization of static data members occurs
(once only!) before any instance initialization or constructor code runs.
The following variation on your program illustrates that the exact same "forward reference" issue can occur for static members:

It prints:
0 10 10
[ August 18, 2002: Message edited by: Ron Newman ]
 
Ranch Hand
Posts: 38
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Barry Gaunt:
In the case of the member variable definition final int j = 10; doesn't compiler say "oh this is a constant, so I just replace j by 10 wherever it appears"? So instead of the variable getting the default value 0 in the first "memory allocate pass" it gets the constant (final) value of 10. Sort of...?
-Barry


It has been interesting reading through the posts on this topic. But, I still am unsure of the quote above. So, yes or no ?
Thank you.
 
Barry Gaunt
Ranch Hand
Posts: 7729
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Rodge, what I had in mind was the C++ compiler's handling of const int j = 10; (which is safer than the C preprocessor's #define j 10)
I have read somewhere (I forgot where) that Java's
final int j = 10; is similar in concept.
-Barry
[ August 20, 2002: Message edited by: Barry Gaunt ]
 
Jose Botella
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Rodge, if you want to know where the value of a variable lives, just use javap -c AClass and if you get something like:
a)getfield-- it was placed in the object image in the heap.
b)getstatic-- it was placed in the class data in the method data area (where classes are loaded)
c)bipush, sipush, dconst, lconst, iconst, fconst
ldc --
the compiler didn't store a variable in the heap or the static area, but it uses a constant value instead.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic