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