How can “this” be referenced/processed before the constructor has concluded?

霸气de小男生 提交于 2019-12-05 07:21:24

That Java Language Specification specifies the steps of instance creation

[...]

Next, space is allocated for the new class instance. If there is insufficient space to allocate the object, evaluation of the class instance creation expression completes abruptly by throwing an OutOfMemoryError.

The new object contains new instances of all the fields declared in the specified class type and all its superclasses. As each new field instance is created, it is initialized to its default value (§4.12.5).

Next, the actual arguments to the constructor are evaluated, left-to-right. If any of the argument evaluations completes abruptly, any argument expressions to its right are not evaluated, and the class instance creation expression completes abruptly for the same reason.

Next, the selected constructor of the specified class type is invoked. This results in invoking at least one constructor for each superclass of the class type. This process can be directed by explicit constructor invocation statements (§8.8) and is described in detail in §12.5.

So by the time the constructor (which is a method) is invoked, your instance exists with default values.

For final fields, it appears those are defaulted as well if you try to access them. For example

public class Driver {

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

    final int value;

    public Driver() {
        print(this);
        value = 3;
    }

    static void print(Driver driver) {
        System.out.println(driver.value);
    }

}

will print 0. I'll be right back with the JLS entry if I can find it.

I couldn't find anything more specific then what is above. Maybe in 4.12.4. final Variables

A final variable may only be assigned to once.

You can take to mean that default initialization puts the value to 0 or null and the assignment changes it.

Once you call your constructor, your object already exists from the start, and you're just populating it with values.

The danger of this comes if the method you're passing your object to tries to use a value that you haven't declared yet in your constructor.


You also want to avoid having your constructor(and other methods for that matter) behave in such a way that the user of the constructor wouldn't expect.

If the person instantiating your object doesn't have a reason to expect the constructor to automatically bind that object to a button, than maybe you shouldn't do that.

this does actually exist before the constructor finishes. However, allowing a reference to this to escape your object before the constructor is complete can present a danger.

What if you passed your this reference to a method that assumes your object is fully formed and ready to go? Maybe this is fine in the case of your object, but in many cases, this could be dangerous. Allowing other methods access to an object before it is ready to be used would present a serious threat to your program being able to run reliably.

You are absolutely right, that is a bad thing to do as this may only be partially initialized at the time you use it.

This is why many compilers will give a warning about doing it.

Don't escape this from the constructor because if another thread read variables of the instance which construction hasn't finished yet, the thread may read unexpected value.

A example is below.

public class A {
  private final int value;
  public A(int value) {
    this.value = value;
    new Thread(new Runnable() { // this escape implicitly
       public void run() {
         System.out.println(value);
       }
    }).start();
  }
  public static void main(String[] args) {
    new A(10);
  }
}

This program may show a value other than 10 from Java Memory Model specification.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!