3 min read

How Autoboxing and Unboxing Works in Java

Autoboxing and unboxing are the automatic conversions done by the Java compiler.
How Autoboxing and Unboxing Works in Java

What is Autoboxing and Unboxing?

Autoboxing is when a primitive type is converted to its wrapper class. Unboxing is when a wrapper class is converted to its primitive type.

Wrapper Classes

Each primitive type has an associated wrapper class.

Primitve type Wrapper Type
boolean Boolean
byte Byte
char Character
float Float
int Integer
long Long
short Short
double Double

Since these are classes, they will be passed by reference instead of by value. If there isn't a value assigned, the value will be null. Also, trying to assign a primitive type the value of null will result in a NullPointerException.

final Integer x = null;
final int x = i;  // NullPointerException

Generics

The biggest reason for wrapper classes is that primitive types cannot be used with generics.

// Invalid Java code
final var items = new ArrayList<int>();

Generics require a class that extends Object, which is every Java class. Since wrapper classes are classes, they extend Object.

To declare the list shown above using the associated wrapper class, you would write it as follows:

final var items = new ArrayList<Integer>();

Examples of Autoboxing and Unboxing

Autoboxing and unboxing can take place when assigning a value to either a variable or method or constructor parameter.

Unboxing

Using integers as an example, unboxing takes place when assigning an Integer value to a primitive int.

final Integer a = 10;
final int b = a;  // unboxing

This will automatically convert the Integer to a primitive int.

Boxing

Once again, using integers, boxing takes place when assigning a primitive int to an Integer.

final int a = 10;
final Integer b = a;  // boxing

This will automatically convert a primitive int into an Integer.

Arithmetic Operators

Using arithmetic operators, the calculation is done using the primitive types.

final Integer x = 11;

if (x % 2 == 0) {
}

These operators don't apply to Integer classes, so the Java compiler will automatically do the following conversion:

final Integer x = 11;

if (x.intValue() % 2 == 0) {
}

The intValue() method converts the Integer object into an int so the operator can be applied.

Equality

Although operators like arithmetic operators work on wrapper classes, checking for equality doesn't always work the same as it does with primitive types.

final int x = 10;
final int y = 10;

// Prints true
System.out.println(x == y);

Doing this same thing using a wrapper class doesn't work the same way. The == operator on classes checks to see if it is the same instance, not if they are equal. What is more confusing is that there are times when it may appear to work.

final int x = 10;
final Integer y = x;
final Integer z = x;

// Prints true
System.out.println(y == z);

Using == in this example evaluates to true, just as you would expect if you were using primitive types. If all you do is change the value of x from 10 to 1000, the == will evaluate to false.

final int x = 1000;
final Integer y = x;
final Integer z = x;

// Prints false
System.out.println(y == z);

Why does simply changing the number change the equality? Once again, these are classes, and you are checking to see if it is the same instance. Java caches numbers between -128 and 127. If you are using a wrapper class and check for equality on this range of numbers, it will work just like primitive values. This is why the first example works but the second one doesn't.

When checking for equality, you either need to convert to primitive types or use the equals() method on a wrapper class.

final int x = 1000;
final Integer y = x;
final Integer z = x;

// Prints true using primitives
System.out.println(y.intValue() == z.intValue());

// Prints true using equals()
System.out.println(y.equals(z));

Booleans

Booleans only have two instances, one for true and one for false. Because of this, you can use == the same way as you would primitive booleans. Also, the Boolean class has constants TRUE and FALSE that can be used as well.

Excluding Booleans, always use the equals() method to check for equality.

Conclusion

Autoboxing and unboxing are automatic conversions. The main reason for it is to turn primitive types into classes and be able to use them with generics. When using wrapper classes, always use the equals() method to check for equality.