Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using 'this' when initializing an instance variable in java?

I've seen this used when declaring an instance variable in IB's API, but this seems like a bad idea. Is assignment guaranteed to occur after this has been fully constructed? Does it matter?

I thought that instance variables were initialized prior to the constructor since they can be used by the constructor. Is there some exception if this is used?

If it somehow works, it doesn't seem like a good idea - is second available to FirstClass's constructor? If so, is SecondClass constructed prior to FirstClass? Which means that num ends up being 3 and i is 10? Or will there be a runtime error? Is there even any guarantee either way?

public class FirstClass {

    SecondClass second = new SecondClass(this);
    public int i = 3;

    FirstClass(){
        i = second.DoSomething();
    }
}

public class SecondClass{

    private int num = 10;

    SecondClass(FirstClass first){
        num = first.i;
    }
    public int DoSomething(){
        return num;
    }
    ...
}

I'd like to think that IB have a pretty solid team of developers and know what they're doing. What do you think:

  1. Can this be used initializing instance variables?
  2. Should it be done?

EDIT

The answer is yes there is a guaranteed result (for now - but read on...), but no it shouldn't be done since its easy to inadvertently make changes to the code that could change this 'guaranteed' result.

I now know that when constructing a new object (such as FirstClass) the JVM:

  1. Allocates memory for all the instance variables of this class and all its superclasses.
  2. Initializes all the variables with default values
  3. "Properly" initializes all the variables in textual order starting from its highest superclasses (i.e. Object) and finishing with this class - so second is initialized (i.e. constructed) prior to i being initialized to 3.
  4. If any of these "proper" initializations call another method or another constructor, this is done before the first constructor is invoked - so second is constructed and returned prior to the FirstClass constructor being run.
  5. If another constructor is invoked by instance initialization (such as in item 4), it goes through the same process from item 1 (memory allocation, initialization etc)

The reason doing this is bad is that the 'guaranteed' result can change in two ways:

  1. If the source code order is changed (e.g. if i is initialized before second is constructed) the result will change. It would be easy not to notice this.
  2. If someone subclasses our class (or classes), they may not be aware of the delicate balance and could change something that affects the result when overwriting.

So it looks like IB's API suffers from this delicacy, which I will have to now keep in mind.

Thanks to Emil H's answer and his direction to this article which ultimately led me to my understanding above: http://www.artima.com/designtechniques/initializationP.html - this is highly recommended reading.

Also thanks to Alexander Drobyshevsky who made a very similar point in his answer.

like image 288
Ben Avatar asked May 09 '26 09:05

Ben


1 Answers

Sure, sometimes you have to use this, for example when a variable given through the Constructor is called as same as a instance variable:

int count;
public Test(int count){  
    this.count = count;
}
like image 163
desperateCoder Avatar answered May 12 '26 11:05

desperateCoder



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!