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.
Code in GitHub

Get the code for this tutorial using the links below.

Project Repo
Download code for this step
Main class for this step
Dependencies

This is a list of recommended tutorials or courses that might be useful before starting this one.

Contents
Welcome to the Course!
Course Introduction
Chapter 1 - Building Blocks
Quick introduction to Java Variables Classes And Objects Class Example - Defining a class Object Examples - Creating instances Java Application Example - Running our first app Accessing class members - The dot operator Packages - Organizing the code
Chapter 2 - Primitives and Operators
Primitives Arithmetic Operators Assignment Operator Unary Operators Equality and Relational Operators Conditional Operators
Chapter 3 - Statements and Control Flow
Expressions Statements If-Then Statement If-Then-Else Statement More If Statements Switch Statement While and Do-While Statements For Statement Branching Statements Exception Handling
Chapter 4 - Code Example
Example Project - A Simple Vending Machine Adding money Delivering Items Giving Change
Chapter 5 - Classes and Interfaces
Introduction Access Level Modifiers Class Declaration - Class, Methods and Fields Class Declaration - Constructors Inheritance Basics Inheritance - Constructors Inheritance - Methods and Fields Polymorphism Abstract Classes and Methods Interfaces Static Class Members Class Composition Final Classes and Class Members Generic Classes
Chapter 6 - Base Object Behaviors
Introduction Type Comparison Type Casting Object Equality - The Contract Object Equality - Common Pitfalls Object String Representation Garbage Collection Object Comparison Primitive Wrappers and Autoboxing
Chapter 7 - Data Structures
Introduction Arrays - Declaration and Creation Arrays - Basic Operations Core Collection Interfaces List and ArrayList - Basic Operations ArrayList Internals Introduction to Hash Tables Map and HashMap - Basic Operations Set and HashSet - Basic Operations
Chapter 8 - Anonymous classes and lambdas
Introduction Filtering a List Anonymous Classes Lambdas Built-in Functional Interfaces
Chapter 9 - Streams
Introduction Creating Streams Intermediate Operations Terminal Operations