• 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
  • Tim Cooke
  • Liutauras Vilda
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Ron McLeod
  • Devaka Cooray
  • Henry Wong
Saloon Keepers:
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Tim Moores
  • Mikalai Zaikin
Bartenders:
  • Frits Walraven

initialization of final instance fields

 
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm quite surprised by the result of the following program:


-------------
Result:
A.newInstance() : i=1 j=0
un()
B.newInstance() : i=1 j=1


Can anyone explain that ? And if possible, the reference to the JLS please.

Thanks in advance.
[ February 23, 2005: Message edited by: Mark Spritzler ]
 
ranger
Posts: 17347
11
Mac IntelliJ IDE Spring
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
First, let's put some CODE tags around your code so that we can read it with correct indentation.

the CODE tags are created when you click the CODE button which is among the buttons under the Add Reply button

Mark
 
Greenhorn
Posts: 15
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello.
Very good example.

First, here is your link: http://java.sun.com/docs/books/jls/index.html

Second, about the program.
There is exact explanation for instantiation in Java Language Spec.
(paragraph 12.5 (page 242 in PDF))

1. Memory is allocated.
2a. If explicit constructor of superclass presents (super()) then it is called
2b. If there is no explicit constructor then implicit constructor is called
(default constructor: super())
3. All instance variables initializers are called
(note, that static initializers are called during class loading)
4. Rest of the body of the constructor is executed.

note that UN is known at compile time
and un() is not (it is method !)
so during memory allocation i is initialized with UN=1
and j is initialized with default =0

when you call B() in main()
you execute following
1. execute A()
2. initialize i and j
3. execute B()

and the output confirms that
 
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You have made an observation that yields a result due to the invocation of an overrideable method on a 'this' reference.
Doing so is incredibly poor form, albeit common.

Here's some more:
http://www.xdweb.net/~dibblego/java/trivia/answers.html#q4
 
Xiaolong KONG
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for the code formating and the replies.

As you cited, according to the JLS, "All instance variables initializers are called" after the call super(). As instance field initializers, both UN (while runtime, it's effectively 1) and un() should be assigned to i or j AFTER the call to A(). However it's not what the program does.

In fact, if we remove the modifier final before the instance field i, we will get 0, 0, 1, 1. So does it mean that the modifier final modifies the initialization ordre of the instance fields ? If so, why it doesn't call un() for the field j before super() in our case?

It's surely not a good example for coding practice, but to better understand the JLS.
 
Evgeni Shuster
Greenhorn
Posts: 15
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
When I said good example, I didn't mean coding practice.
It is good example of question to prepair for Programmer Exam.

May be my explanation of why i=1 was too short.
I wrote:


note that UN is known at compile time
and un() is not (it is method !)
so during memory allocation i is initialized with UN=1
and j is initialized with default =0


You should have good understanding of what is "instance variable initializer" and what is not.
In our case:

is initializer, but:

is not initializer, because i is final and UN is compile time constant.
You can find exect definition of instance (and static) variable initializers in JLS (probably somewhere in "Statements" or "Expressions" parts).
 
Xiaolong KONG
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Evgeni,

I agree with you that it's a good example for the SCJP, it's also why I post it in this forum.

In you last response, you missed the point of "instance variable initializer" yourself.


and


are both instance variable initializers, as indicated in the �8.6 of JLS.

In fact, the key point in this example is the keyword final. If we remove it, even

is not invoked before the call to super() and the instance variable i will has its default value: 0.

Does anyone have an idea about the initialization of final instance fields?
 
Evgeni Shuster
Greenhorn
Posts: 15
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello,
I made a mistake, it's so sad
Thank you Xiaolong for noticing it.
is initializer.
And it must be called after A().

May be it is some kind of optimization
UN is compile time constant, and i is final.
May be compiler hints to JVM to initialize i with 1 and not with default 0.
It makes sense in every case except our example.
And test shows that it happens on practice.

Do one more test with the program.
replace line with
then add to be first line of constructor B().
Class B now looks like this:

Compile it and run.
It prints i=0, j=0 for A and i=1, j=1 for B.

Note that i is still final here!
Interesting, we use final variable i even before it is assigned!
(check chapter 16 in JLS)

Where did you get this example? Is there anything else as good as this one?
[ February 24, 2005: Message edited by: Evgeni Shuster ]
 
Ranch Hand
Posts: 298
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Go thru the link in JLS
here

It says that "static variables that are final and that are initialized with compile-time constant values are initialized first".

But when u change the value not to be a final. It doesnt get initialized during the Class initialization and so the value is not set even though it points to a compile time constant.
 
Evgeni Shuster
Greenhorn
Posts: 15
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
to Animesh
Nobody has problem with STATIC and final variables.
UN is static and final and it is initialized with compile time constant 1.
But i is NOT static, so why i is initialized before constructor A() ?
And how it is possible to use final i in second test even BEFORE the value is assigned to it?
 
Ranch Hand
Posts: 1272
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

why i is initialized before constructor A()


A class's initializers are executed before its constructors (not counting the first lines of the constructors).
 
Ranch Hand
Posts: 443
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Mike Gershman:

A class's initializers are executed before its constructors (not counting the first lines of the constructors).



Yes, but i is not a class variable.

A blank final instance variable is allowed as long as it is assigned at the end of the constructor. And in the modified version of program B, the variable i, which is an instance variable of class B (NOT A), is assigned.
[ February 25, 2005: Message edited by: Alton Hernandez ]
 
Evgeni Shuster
Greenhorn
Posts: 15
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
to Mike

i is not class (=static) variable, it is an instance variable.

to Alton

According to the chapter 16 in JLS:
blank final field must have definitly assigned value when any access of it's value occurs
in modified version we access value of i ( in constructor A() ) before we assign value to it ( in constructor B() )

I still think, the reason for wrong behaviour is somewhere in implementation of JVM (some kind of optimization or just bug
[ February 25, 2005: Message edited by: Evgeni Shuster ]
 
Mike Gershman
Ranch Hand
Posts: 1272
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I apologize for my ambiguous language. What I should have said is:

When an object is being instantiated, the order of execution is:
1. All its instance variables are assigned their default values (0, false, or null).

2. instance variable initialization expressions and instance initialization blocks, in the order they appear in the source code.

3. the constructors, starting after the first (super() or this()) line, in the reverse order of call.
[ February 25, 2005: Message edited by: Mike Gershman ]
 
Alton Hernandez
Ranch Hand
Posts: 443
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Evgeni Shuster:

to Alton
According to the chapter 16 in JLS:
blank final field must have definitly assigned value when any access of it's value occurs
in modified version we access value of i ( in constructor A() ) before we assign value to it ( in constructor B() )

I still think, the reason for wrong behaviour is somewhere in implementation of JVM (some kind of optimization or just bug
[ February 25, 2005: Message edited by: Evgeni Shuster ]



The specification is not violated if you see i as part of an instance of B(), and not of A().

You must also differentiate between a default initial value from a proper initial value. A blank final variable will be initialized to a default initial value during the initialization phase. But it needs a proper initial value before its used because it is deemed as constant

Here, try this modified A class:

 
Evgeni Shuster
Greenhorn
Posts: 15
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
to Alton
According to JLS here
I will copy it for convenience:


Each local variable (�14.4) and every blank final (�4.5.4) field (�8.3.1.2) must have a definitely assigned value when any access of its value occurs. A Java compiler must carry out a specific conservative flow analysis to make sure that, for every access of a local variable or blank final field f, f is definitely assigned before the access; otherwise a compile-time error must occur.



I understand your point.
But I have few more questions.

i is variable of B and is accessed in A, so you allow this
(it's ok, couse JVM allows this too )
then, with some use of polymorphism, we have execution flow that accesses i
A.main() --> B() --> A() --> B.getI()
I think this must be forbidden (as I understand JLS)

lets do one more test
1. add following method to A

2. add following method to B

3. add following line to be first line in constructor B()


Now the program looks like:


It prints:
A.newInstance() : i=0 j=0
un()
i = 0
B.newInstance() : i=1 j=1


here I access i in B before assigning a value to it,
and this looks even more forbidden than accessing it in A

How does this happen?

And one more question: Why in the original example
(posted by Xiaolong KONG) i gets value before call to constructor A() ?
 
Tony Morris
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The important point here is that calling an overrideable method on a 'this' reference from a constructor is pure evil.

Bloch also makes mention of this in "Effective Java" iirc.
 
Animesh Shrivastava
Ranch Hand
Posts: 298
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I agree with what Alton says


You must also differentiate between a default initial value from a proper initial value. A blank final variable will be initialized to a default initial value during the initialization phase. But it needs a proper initial value before its used because it is deemed as constant



By Evgeni


here I access i in B before assigning a value to it,
and this looks even more forbidden than accessing it in A



The above statement by Alton makes it clear that a blank final variable will be initialized with a defualt value(0 here). But it needs a proper initial value. So whatever way u access it, "i" has the defualt value 0 before its explicit initialization.
 
Evgeni Shuster
Greenhorn
Posts: 15
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I perfectly understand what Alton says.
I just say that it should not work this way.
In first example instance variable initializer executed before super constructor (must be after, according to JLS).
In second and third examples final field accessed before a value is assigned to it. (final field must have PROPER value before first access to it)
It is impossible to do thease things without using super constructor.

Note that Alton says:... it needs a proper initial value before its used ...
He just allows use of i in A, because i is not part of A.
But this allows access to initial (not proper) value of i from B.
But really there is nothing to do here.
Just to learn this problem and take care in our own programs.

to Tommy
All thease is not more evil than your changing of immutable Strings inside JVM. Dangers of such tricks were clear from the begginning.
But thank you for mentioning "Effective Java".
 
Alton Hernandez
Ranch Hand
Posts: 443
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Evgeni Shuster:
I perfectly understand what Alton says.
I just say that it should not work this way.
In first example instance variable initializer executed before super constructor (must be after, according to JLS).
In second and third examples final field accessed before a value is assigned to it. (final field must have PROPER value before first access to it)
It is impossible to do thease things without using super constructor.



Hi Evgeni,

To further understand this, let us simplify the program. First, create two files, A.java amd B.java:


If you run and compile all these program, you will get an output of:
A() getI():0
B() getI():0

If you remove line 2 in B, the program will not compile simply because i must be definitely assigned before the end of every constructor.

Now, modify A and change any reference to getI() to getII(), like this:
A.java
class A {
int i=3;
int getII() {return i;}
A() {
System.out.println("A() getII():" + getII());
}
}
[/code]


Now compile A.java only and then run B. Your output will come out like this:
A() getI():3
B() getI():0

The point here is that the call by the A class to the overridden getI() function is done on runtime. So when you compile B(), the compiler has no knowledge that a reference to a blank final variable is being called from A.
 
What a show! What atmosphere! What fun! What a tiny ad!
Gift giving made easy with the permaculture playing cards
https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
reply
    Bookmark Topic Watch Topic
  • New Topic