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?

The Student
  • 27,520
  • 68
  • 161
  • 264

5 Answers5

6

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
  • 10,751
  • 3
  • 30
  • 46
  • 1
    Thanks! And this leads to http://stackoverflow.com/questions/2547713/why-static-fields-are-not-initialized-in-time – The Student Mar 30 '10 at 18:39
  • This is from a long time ago, but I just want to say that although this can't happen, it does to me. The only thing I can think of is that it's because it's GWT that I'm dealing with, so it's Java that's cross-compiled to JScript. – Jamie Jan 06 '17 at 01:28
3

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
  • 25,562
  • 6
  • 51
  • 57
2

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
  • 80,905
  • 18
  • 123
  • 145
2

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
  • 28,823
  • 13
  • 72
  • 81
  • it was not my negative, but what are you talking about? – The Student Mar 30 '10 at 18:36
  • 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 Mar 30 '10 at 19:39
  • +1 - see also https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=32833640 – Simon Nickerson Mar 30 '10 at 20:59
2

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
  • 42,159
  • 20
  • 102
  • 127