views:

135

answers:

5

Is it true that the assigned final object field may still be null inside a constructor?

class MyClass {
  private final Object obj = new Object();
  public MyClass() {
    System.out.println(obj); // may print null?
  }
}

if yes, isn't this a bug?

+2  A: 

The initializer Object obj = new Object(); will run before the code inside the constructor, so obj cannot be null.

Note that this would not compile if you did not initialize obj anywhere.

danben
+1  A: 

Works for me:

$ cat MyClass.java
class MyClass {
    private final Object obj = new Object();
    public MyClass() {
        System.out.println(obj); // may print null?
    }
    public static void main(String[] args) { new MyClass(); }
}
$javac MyClass.java; java MyClass
java.lang.Object@19908ca1

All field initializers are copied by the compiler into the begining of all constructors.

However, under the Java 5 memory model, if you let the this reference 'escape' before the end of the constructor, other threads can see uninitialized values of final fields (so could see null in this case).

Ben Lings
it was not my negative, but what are you talking about?
Tom Brito
The last paragraph describes the only situation I know of where it's possible to see the value of a final field having its uninitialized value. See the "How do final fields work under the new JMM?" section of http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html
Ben Lings
+1 - see also https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=32833640
Simon Nickerson
+1  A: 

This is not possible as the as all initializers run before the constructor is invoked.

Variable initializers like you have private final Object obj = new Object(); run before the constructor is invoked. This is also true of initialisation blocks static or otherwise.

One thing to watch out for when using initializers is that initializers can't make forward references When you write an initializer, you cannot refer to any instance variables declared textually after the variable being initialized.

Tendayi Mawushe
+2  A: 

As discussed by other answers, no, that can not happen. With an assigned final static field, however, it can.

class MyClass {
  private static MyClass myClass = new MyClass();
  private static final Object obj = new Object();
  public MyClass() {
    System.out.println(obj); // will print null once
  }
}
ILMTitan
Thanks! And this leads to http://stackoverflow.com/questions/2547713/why-static-fields-are-not-initialized-in-time
Tom Brito
A: 

With a simple example like yours, nothing bad can happen. However, it is possible for a final field to be visible as uninitialised if you use questionable practices such as calling an overridable method in your constructor.

For example, the following program prints "My favourite colour is null", even though it references the final variable favouriteColour, which is set to "blue" in the constructor.

abstract class SuperClass {
    final String favouriteColour;

    SuperClass() {
        announceFavouriteColour();
        favouriteColour = "blue";
    }

    abstract void announceFavouriteColour();
}

public class FinalTest extends SuperClass {
    void announceFavouriteColour() {
        System.out.println("My favourite colour is " + favouriteColour);
    }

    public static void main(String[] args) {
        new FinalTest();
    }
}
Simon Nickerson