Boxing was introduced in JDK 1.5 to eliminate trivial conversions between primitives (int, boolean, etc) and corresponding wrapper objects (Integer, Boolean, etc). Boxing allows code to be a bit more concise and legible.

There are two complimentary aspects of boxing :

  • auto-boxing, which refers to automatic conversion of an int to an Integer, for example
  • auto-unboxing, which refers to automatic conversion of a Boolean to a boolean, for example

Boxing is useful when using collections. It is also useful more generally, where trivial conversions between a primitive and a wrapper object (or vice versa) are needed.

Some points to remember :

  • auto-unboxing a null object will cause a NullPointerException
  • boxing does not eliminate conversions, it merely performs them on your behalf. As a tiny performance optimization, one might explicitly avoid boxing to eliminate the small cost of these conversions.

The rules for comparison of primitives and wrapper objects are as follows.

If x and y are either both primitives, or both objects, then no boxing can occur :
 

Operation x and y  are primitives x and y are objects
x == y compare value compare identity
x.equals(y) does not compile compare value

If one item is a primitive, and the other item is a corresponding wrapper object, then boxing can occur :
 

Operation Behavior
x == y treat as two primitives, and compare value
x.equals(y) does not compile if x is a primitive ; otherwise treat as two objects, and compare value

Example

import java.util.*;

public final class BoxingExamples {

  public static final void main(String... aArgs){
    //pass Integer where int expected
    explode(new Integer(3));

    //pass literal where Boolean expected
    tellTruth(true);

    //calculate "int-erchangably" with int and Integer
    Integer integerYear = new Integer(1989);
    Integer otherIntegerYear = integerYear + 10;
    int intYear = integerYear + new Integer(15);
    log(integerYear.toString());
    log(otherIntegerYear.toString());
    System.out.println(intYear);

    /*
    * Comparison of primitives and wrapper objects using == and equals.
    *
    * When both items are of the same type :
    *             2 primitives          2 objects
    * ----------------------------------------------------------
    * ==       :  value                 identity
    * equals() :  not applicable        value
    *
    *
    * When one item is a primitive, and the other is an object :
    * ==          :  treat as two primitives
    * x.equals(y) :  treat as two objects; do not compile if x is primitive
    */
    intYear = 1880;
    integerYear = new Integer(1880);
    if ( intYear == integerYear ){
      log("intYear == integerYear: TRUE"); // yes
    }
    else {
      log("intYear == integerYear : FALSE");
    }
    if ( integerYear.equals(intYear) ){
      log("integerYear.equals(intYear): TRUE"); //yes
    }
    else {
      log("integerYear.equals(intYear): FALSE");
    }
    //does not compile "int cannot be dereferenced" :
    //intYear.equals(integerYear);

    intYear = 1881; //new value
    if ( intYear == integerYear ){
      log("intYear == integerYear: TRUE");
    }
    else {
      log("intYear == integerYear : FALSE"); // yes
    }
    if ( integerYear.equals(intYear) ){
      log("integerYear.equals(intYear): TRUE");
    }
    else {
      log("integerYear.equals(intYear): FALSE"); //yes
    }
  }

  // PRIVATE //
  private static void explode(int aNumTimes){
    log("Exploding " + aNumTimes + " times.");
  }

  private static void tellTruth(Boolean aChoice){
    //instead of if ( aChoice.booleanValue() ) {
    if ( aChoice ) {
      log("Telling truth.");
    }
    else {
      log("Lying like a rug.");
    }
  }

  private static void log(String aText){
    System.out.println(aText);
  }
}

An example run of this class :

>java -classpath . BoxingExamples
Exploding 3 times.
Telling truth.
1989
1999
2004
intYear == integerYear: TRUE
integerYear.equals(intYear): TRUE
intYear == integerYear : FALSE
integerYear.equals(intYear): FALSE

Advertisements