Chapter 6 - Java for Beginners Course

Primitive Wrappers and Autoboxing

One of the special behaviors provided by the Java compiler is the autoboxing and auto-unboxing performed between primitive types (like int) and what are called the wrapper classes (like Integer) which we’ll introduce first.

Are primitive types objects?

No, in Java the primitive types aren’t objects. However, Java provides equivalent classes for all the primitive types called Wrapper Classes.

For every primitive type, we have an equivalent type as shown in the following table:

Primitive type Wrapper class Primitive type Wrapper class

boolean

Boolean

int

Integer

byte

Byte

long

Long

short

Short

float

Float

char

Character

double

Double

Boxing and Unboxing

Java allows us to interchangeably move from a primitive type to the corresponding wrapper class (boxing) or vice-versa (unboxing) if required, for example, we could do:

int anInt = 10;
Integer boxed = anInt;

Java would automatically return an Integer object on the second line that represents the value 10. This is called auto-boxing.

We could also go the other way around, for example:

Integer anInteger = 10;
int unboxed = anInteger;

In this case, on the second line Java would auto-unbox the value from the Integer object and assign 10 to the unboxed variable.

Why do we need the wrapper classes?

There are different reasons why you’d need to use a wrapper class instead of their corresponding primitive type. In some cases, you don’t need to use them explicitly as the Java compiler will use them behind the scenes (via autoboxing).

Some of these scenarios are:

Invoking methods that receive an object as a parameter

Let’s assume you have the following class that you’re using from a library:

public class ObjectPrinter {
    public void printObject(Object objectToPrint) {
        System.out.println(objectToPrint);
    }
}

The printObject provided by this method doesn’t operate on primitives. The class of course, could provide overloaded methods to cover all the different primitive types, like printObject(int x) to allow users of the class to also use primitives, but that would be redundant.

However, as Java supports autoboxing, this method already works correctly when you pass a primitive type, for example:

In the example code run the JavaWrapperClassesApp
int numberToPrint = 10;
ObjectPrinter printer = new ObjectPrinter();
printer.printObject(numberToPrint);

Output:

10

This is one of the cases where we are using wrapper classes without indicating it explicitly. The Java compiler knows that the parameter to the printObject method is an Object and knows it must convert our int value into an Integer object to invoke the method.

As a result of autoboxing, we don’t get any compilation errors and the program runs fine.

Using constants and static helper methods defined in the wrapper classes

All the wrapper classes provide useful constants and helper methods that can be used to perform common operations, like converting a String to an Integer. We saw a couple of example in the section about abstract classes where we converted a number into its binary and hexadecimal representation.

An example of one of these static helper methods is the Integer.parseInt method that is used to convert a String to an int value:

int value = Integer.parseInt("-10");
System.out.println(value);

Output:

-10

Use in generic classes

When defining type parameters for generic classes, Java only accepts classes or interfaces. This means that primitive types can’t be used as type parameters.

For example, let’s assume we have the following Gift<T> class (adapted from a previous section):

public class Gift<T> {
    private T item;

    private String from;

    private String to;

    public Gift(T item, String from, String to) {
        this.item = item;
        this.from = from;
        this.to = to;
    }

    public T getGiftItem() {
        return item;
    }

    @Override
    public String toString() {
        return "Gift [item=" + item + ", from=" + from + ", to=" + to + "]";
    }
}

And let’s assume we want to represent a monetary gift, like $10. Let’s assume the monetary amount is an integer value, so we could think about doing:

Gift<int> monetaryGift = new Gift<>(10, "Jane", "John");

This isn’t valid for the reasons mentioned above, so we need to use the corresponding primitive wrapper, like this:

Gift<Integer> monetaryGift = new Gift<>(10, "Jane", "John");
System.out.println("The gift is: " + monetaryGift);

Output:

The gift is: Gift [item=10, from=Jane, to=John]
This will become even more relevant when we introduce data structures in the next chapter.