8

I wrote this piece of code and it seems compiler allows accessing uninitialized blank final field when accessed using 'this' keyword:

public class TestClass
{
    public final int value1;
    public int value2;

    TestClass(int value) {
        value2 = 2 + this.value1; // access final field using 'this' before initialization gives no compiler error
        //value2 = 2 + value1;      // uncomment it gives compile time error - variable value1 might not have been initialized
        value1 = value;
    }

    public static void main(String args[]) {
    TestClass tc = new TestClass(10);
    System.out.println("\nTestClass Values : value1 =  " + tc.value1 + " , value2 =  " + tc.value2);
    }
}

I tried compiling it on 1.5, 1.6, & 1.7 and got same result in all three of them.

To me it looks like compiler bug because compiler must throw error in this case but with 'this' keyword it doesn't and thus creates scope of coding error as it will go unnoticed by the programmer since no compile-time or run-time error will be thrown.

FEW POINTS WHY IT IS NOT A DUPLICATE
- all answers are explaining how it works and what JLS says, fine, but my real intent here is should that be allowed at the first place?
- my question here is more from programmer's point of view and not language semantics

sactiw
  • 21,935
  • 4
  • 41
  • 28

3 Answers3

1

In Java ints have a default value of 0, so even if you did not initialize it, the compiler has still assigned 0 as value.

Fields that are declared but not initialized will be set to a reasonable default by the compiler. Generally speaking, this default will be zero or null, depending on the data type.

Source: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

Note that this does not apply to local variables, only field variables have a default value.

user2610529
  • 491
  • 3
  • 10
  • 3
    But why does adding `this` change how that works? – Thilo Jun 16 '14 at 09:19
  • http://stackoverflow.com/q/3789528/3492139 – ngrashia Jun 16 '14 at 09:20
  • 1
    @user2610529 Here we are talking about 'final' fields which should not be accessed without first being initialized. And moreover my complain is about compiler's behavior which is deviating in the two cases i.e. without 'this' keyword it complains but with 'this' keyword it doesn't. – sactiw Jun 16 '14 at 09:23
  • "Note that this does not apply to local variables". It does not apply to *final* fields either. You must assign a value to them. – Thilo Jun 16 '14 at 09:25
  • @Thilo exactly, that's my question is all about – sactiw Jun 16 '14 at 09:25
  • 1
    In the linked question there is a good answer for this. http://stackoverflow.com/a/13867012/2610529 – user2610529 Jun 16 '14 at 09:27
1

This is not a bug. This a feature for Java Specification 1.6 and lower.

The final field can be accessed at any part of the code. There is no restriction about it.

The only restriction in case of final is that it has to be initialized before class instance is created.

When you use this, you express that it is element of the object that is being constructed.

Since the specification 1.7 because of change we may say that this is bug in some implementation of compilers.

But since 1.8 the code will produce same error for this.value1 or value1.

Community
  • 1
  • 1
  • May be it is not but it does wide opens scope for a programmer to introduce a bug. For example, here my intention was to set value2 = 2 + value1 where value1 should be preset to value passed to the constructor. But in this case value2 will always be 2 as uninitialized blank final field 'this.value1' holds 0 at that point and compiler is letting me access it. – sactiw Jun 16 '14 at 09:32
  • You can not call this a bug. This is how it was specyfied. In JVM version 7. The specification has changed and because o that this will be a compile time error. – Damian Leszczyński - Vash Jun 16 '14 at 10:07
  • two points: (1) I compiled above code with Javac 1.7.0_09 and didn't get any compile time error (so issue is still there). (2) If this isn't/wasn't a bug (rather a feature as you said in your reply) why would they fix it at the first place in new versions, if at all. – sactiw Jun 17 '14 at 09:25
  • Cause of the confusion is that this is hidden in JVM specification. In case of Java Spec v1.6 this is a feature. But for Java Spec v1.7 this is bug. Because the specification has changed. There is a distinction between accessing object via simple name and qualified by `this`. For 1.8 will not compile. The origin of change is changes in specification. I think this solves your confusion. – Damian Leszczyński - Vash Jun 17 '14 at 10:08
  • 2
    +1 for "Since the specification 1.7, because of change we may say that this is bug in some implementation of compilers." But whether you agree or not and irrespective of what JLS of previous versions says I see it as a bug because it let me introduce one in my code. :P – sactiw Jun 17 '14 at 10:41
0

I used the following code

public class HelloWorld {

    public final int value1;
    public int value2;
    public HelloWorld(int value){
        System.out.println(this.value1);
        System.out.println(this.value2);
        value1 = value;
    }

    public static void main(String args[]) {
    }
}

and the bytecode it generates is

Compiled from "HelloWorld.java"
public class test.HelloWorld extends java.lang.Object{
public final int value1;

public int value2;

public test.HelloWorld(int);
  Code:
   0:   aload_0
   1:   invokespecial   #11; //Method java/lang/Object."<init>":()V
   4:   getstatic       #14; //Field java/lang/System.out:Ljava/io/PrintStream;
   7:   aload_0
   8:   getfield        #20; //Field value1:I
   11:  invokevirtual   #22; //Method java/io/PrintStream.println:(I)V
   14:  aload_0
   15:  iload_1
   16:  putfield        #20; //Field value1:I
   19:  return

public static void main(java.lang.String[]);
  Code:
   0:   return

}

If you notice JVM does a getstatic call in case of final and getfield in case of normal instance variable. Also now if you look at the specs for getstatic it says

On successful resolution of the field, the class or interface that declared the resolved field is initialized (§5.5) if that class or interface has not already been initialized.

So if you use this with a final variable then it is initialize it. Not it will initialize this.value1 and not value1 which is final. You still have to initialize it before using.

Aniket Thakur
  • 66,731
  • 38
  • 279
  • 289
  • The `getstatic` loads `System.out`, not `value1`. Interestingly I only see a single invocation of `println` where your code has 2. – Mark Rotteveel Jun 16 '14 at 09:42