How to "this" reference / handle until the constructor completes?

The specific use when I thought about this problem is as follows, but it is much more generalized.

I have my own JFrame class, which also serves as an ActionListener for its components. So my constructor looks something like this:

 private JButton myButton; public MyCustomFrame() { super(); myButton.addActionListener(this); // ... more stuff } 

My question is, how does this really work behind the scenes? If the constructor is what “creates” the object referenced by this , how can I use this until the constructor returns? The code compiles and works just fine (as far as I can tell), so the object should already "exist" in a way, but I'm worried that this could cause unforeseen problems. Is there any danger when passing a "partially constructed" link to addActionListener() (or just executing any logic with it at all)? Or is there some kind of disguising magic that keeps me safe?

For example, what about things that do not have default values ​​and should be provided by the constructor? If I am declared private final String SOME_VALUE; , I understand that this should be null by default, but the object should not be fully formed until a constant is provided with a value inside the constructor. So will the link, although it is final, possibly change the meaning?

+6
source share
5 answers

This Java language specification specifies the steps to create an instance.

[...]

Next, an instance of the new class is allocated . If there is not enough space to place the object, the class evaluation instance expression terminates abruptly, throwing an OutOfMemoryError.

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

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

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

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

For final fields, they are displayed by default if you are trying to access them. for instance

 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 will return with a JLS entry if I find it.

I could not find anything more specific than the one above. Perhaps in 4.12.4. final variables

The final variable can only be assigned once.

You can understand that initialization sets the value to 0 or null by default, and the destination changes it.

+9
source

As soon as you call your constructor, your object already exists from the very beginning, and you just fill it with values.

The danger of this occurs if the method by which you pass your object tries to use a value that you have not yet declared in your constructor.


You also want your constructor (and other methods, for that matter) to behave in a way that the constructor user does not expect.

If the person creating the instance of the object has no reason to expect the constructor to automatically bind this object to the button, perhaps you should not.

+4
source

this does exist until the constructor completes. However, to link to this to avoid your object until the constructor completes, it can be dangerous.

What if you passed the this link to a method assuming your object is fully formed and ready to go? This may be good in the case of your facility, but in many cases it can be dangerous. Providing other methods of access to the object until it is ready for use poses a serious threat to the reliable operation of your program.

+1
source

You are absolutely right, this is bad, because this can only be partially initialized when you use it.

This is why many compilers will warn about this.

+1
source

Do not avoid this from the constructor, because if another thread reads instance variables whose construction is not yet complete, the thread may read an unexpected value.

An 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 can display a value other than 10 from the specification of the Java Memory Model.

0
source

All Articles