Don't pass 'this' out of a constructor

Within a class, the 'this' Java keyword refers to the native object, the current instance of the class. Within a constructor, you can use the this keyword in 3 different ways:

You can get into trouble with the last form. The problem is that, inside a constructor, the object is not yet fully constructed. An object is only fully constructed after its constructor completely returns, and not before. But when passed as a parameter to a method of some other object, the this reference should always refer to a fully-formed object.

This problem occurs mainly with listeners. Here's an example which illustrates the point:


import java.util.Observable;
import java.util.Observer;

/**
 @author javapractices.com
 @author Andrew Sackett
*/
public final class EscapingThisReference {

  /** A RadioStation is observed by the people listening to it. */
  static final class RadioStation extends Observable {
    //elided
  }
  
  /** 
   A listener which waits until this object is fully-formed before
   it lets it be referenced by the outside world.
   Uses a private constructor to first build the object, and then 
   configures the fully-formed object as a listener. 
  */
  static final class GoodListener implements Observer {
    /** Factory method. */
    static GoodListener buildListener(String aPersonsName, RadioStation aStation){
      //first call the private constructor
      GoodListener result = new GoodListener(aPersonsName);
      //the 'result' object is now fully constructed, and can now be
      //passed safely to the outside world
      aStation.addObserver(result);
      return result;
    }
    @Override public void update(Observable aStation, Object aData) {
      //..elided
    }
    private String fPersonsName;
    /** Private constructor. */
    private GoodListener(String aPersonsName){
      this.fPersonsName = aPersonsName; //ok
    }
  }
  
  /** 
   A listener which incorrectly passes a 'this' reference to the outside world 
   before construction is completed.
  */
  static final class BadListenerExplicit implements Observer {
    /** Ordinary constructor. */
    BadListenerExplicit(String aPersonsName, RadioStation aStation){
      this.fPersonsName = aPersonsName; //OK
      //DANGEROUS - the 'this' reference shouldn't be passed to the listener,
      //since the constructor hasn't yet completed; it doesn't matter if 
      //this is the last statement in the constructor!
      aStation.addObserver(this);
    }
    @Override public void update(Observable aStation, Object aData) {
      //..elided
    }
    private String fPersonsName;
  }
  
  /** 
   Another listener that passes out a 'this' reference to the outside 
   world before construction is completed; here, the 'this' reference 
   is implicit, via the anonymous inner class.
  */
  static final class BadListenerImplicit {
    /** Ordinary constructor. */
    BadListenerImplicit(String aPersonsName, RadioStation aStation){
      this.fPersonsName = aPersonsName; //OK
      //DANGEROUS
      aStation.addObserver(
        new Observer(){
          @Override public void update(Observable aObservable, Object aData) {
            doSomethingUseful();
          }
        }
      );
    }
    private void doSomethingUseful() {
      //..elided
    }
    private String fPersonsName;
  }
}
 


See Also :
Constructors in general
Constructors shouldn't start threads
Would you use this technique?
Yes   No   Undecided   
© 2014 Hirondelle Systems | Source Code | Contact | License | RSS
Individual code snippets can be used under this BSD license - Last updated on September 21, 2013.
Over 2,000,000 unique IPs last year - Built with WEB4J.
- In Memoriam : Bill Dirani -