CIT 591 Wrappers and Autoboxing/unboxing
Fall 2009, David Matuszek

The problem

Java has both primitives (int, double, boolean, char, etc.) and Objects. It also has a whole set of "collection" classes, to represent lists, sets, maps (dictionaries), and the like. For our purposes, we'll talk only about the ArrayList, which is a lot like a Python list (but without the nice syntax). You would use an ArrayList when you want something like an array, but want to be able to let it grow as you add things to it.

The problem is that collections can only hold objects. Thus, you can have an ArrayList<String> (an ArrayList containing Strings), but you cannot have, for example, an ArrayList<int>.

The old solution

For this reason (among others), Java defines a wrapper class for each kind of primitive. Corresponding to doubles there is a Double class; corresponding to booleans there is a Boolean class, and so on. The wrapper class for each kind of primitive has the same name as the primitive, but capitalized; with two exceptions: The wrapper class for int is called Integer, and for char it's called Character.

To put an integer, say n, into an Integer object, nw, you would say Integer nw = new Integer(n). To get the int out of an Integer object, you would say nw.getIntValue(). Similar constructions apply for the other seven primitive types.

The new solution

Since the old solution involves you putting a wrapper on your primitives so that you can store them in a collection, then you unwrapping them when you take them back out, why not have the compiler do this automatically for you?

Whenever you try to use a primitive where an Object is required, the primitive will be automatically wrapped (autoboxed) for you. Whenever you try to use a wrapped primitive where a primitive is required, it will be automatically unwrapped (auto-unboxed) for you. This isn't just for collections; it happens everywhere.

You still cannot declare an ArrayList<int>, but you can declare an ArrayList<Integer>. So here are some things that work fine:

        Integer wrap = 10;
        int unwrapped = wrap;
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(unwrapped);
        int n = list.get(0);

This is the good side of autoboxing/unboxing; you don't have to wrap/unwrap yourself. But it also has a dark side:

    public static void main(String[] args) {
        Integer a = 127;
        Integer b = 127;
        Integer c = 128;
        Integer d = 128;
        System.out.println(a + " == " + b + " is " + (a == b));
        System.out.println(c + " == " + d + " is " + (c == d));
    }
prints
  127 == 127 is true
  128 == 128 is false