Fwd: inner class reading uninitialized value from outer class

Alex Buckley alex.buckley at oracle.com
Thu Jun 23 00:36:05 UTC 2016


On 6/22/2016 5:08 PM, Jonathan Gibbons wrote:
> As the owner of the compiler-dev list, I'm forwarding this email that
> was bounced here from the jls-jvms-spec-comments at openjdk.java.net list.

Thanks Jon.

> On 06/22/2016 04:54 PM, compiler-dev-owner at openjdk.java.net wrote:
>> Subject:
>> inner class reading uninitialized value from outer class
>> From:
>> Xen <list at xenhideout.nl>
>> Date:
>> 06/05/2016 07:10 AM
>>
>> To:
>> jls-jvms-spec-comments at openjdk.java.net
>>
>> I am not sure if this is the proper list to discuss a thing like this.
>>
>> The only alternative I have really found thus far is compiler-dev.
>>
>> I created an inner class that reads a value from the outer class:
>>
>>
>> class Outer {
>>   final int value;
>>
>>   Outer() {
>>     value = 1;
>>   }
>>
>>   class Inner {
>>     int mine = Outer.this.value;
>>   }
>> }
>>
>> Now an instance of inner is created before the constructor of outer is
>> called.
>>
>> The OpenJDK 8 compiler gives no error, but the value that is getting
>> read is 0; even though it has not been initialized (no oddity here)
>> but it is getting read even though it is not initialized; and there is
>> no compiler warning saying so:
>>
>> class Outer {
>>   Inner haha = new Inner(); // gets initialized to 0, not to 1
>>
>>   ...
>> }

Per JLS 12.5, the instance variable 'haha' is initialized prior to 
execution of Outer's constructor. This causes execution of 'new 
Inner()', which causes the instance variable 'mine' of Inner to be 
initialized, which causes an access to the 'value' field of the (still 
being created) Outer object which is the lexically enclosing instance of 
the (still being created) Inner object per JLS 15.9.2. That 'value' 
field is still at its default value of 0, since Outer's constructor has 
not yet run for the (still being created) Outer object. The access is 
not advisable, but definite assignment analysis cannot prevent it, so 
ultimately it's acceptable.

>> However if we put the creation into the constructor of outer, it gets
>> the proper value. So there are 2 init stages: before the constructor
>> is called, and after. You can call both inner class pre-init and
>> constructor (both instanced) before the outer class constructor has
>> been called.

This is all true.

>> Nothing odd here, but it does read a final value that has not been
>> initialized yet. Maybe this should simply be a compiler error. I don't
>> know what the spec says about this. It will just compile fine on
>> openjdk 8 (I got a package error trying to install 9 on my system,
>> hence I am using 8 for (this) now).
>>
>> Basically I wonder if the spec allows this, or whether this is a
>> compiler error.

The spec allows this. It is possible to do all kinds of crazy things as 
a result of the language allowing arbitrary code in instance variable 
initializers, instance initializers, static variable initializers, and 
static initializers.

Alex


More information about the compiler-dev mailing list