Free for students · Ad-free · WCAG 2.1 AA Compliant · Accessibility

Wrapper Classes

Lesson ~11 min read 8 MCQs

In simple terms: In simple terms, wrapper classes let you treat simple numbers like `int` and `double` as full-fledged objects, which is necessary for data collections like `ArrayList`.

Why this matters

Imagine you're at an arcade in Dallas. You have a pocketful of plain cash ($5, $10). That cash is simple, fast, and great for buying a soda from the vending machine. But to play any of the arcade games, you need to go to the counter and exchange your cash for game tokens.

Those tokens represent the same value as your cash, but they're in a form the machines understand. They're "wrapped" in a new format.

In Java, our primitive types like int and double are like that cash. They're efficient and straightforward. But some powerful tools, like the ArrayList we've been using, are like the arcade games—they only work with objects, not primitives.

So, what do we do? We need a way to "wrap" our primitive values into object form. That's exactly what wrapper classes do. We'll explore how Java helps us do this, sometimes so automatically it feels like magic.

Concept overview

flowchart TD
    subgraph Autoboxing
        A[primitive int value e.g. 42] --> B{Context needs an Object?<br/>e.g. ArrayList.add()};
        B -- Yes --> C[Java automatically creates<br/>new Integer object];
        C --> D[Integer object holding 42];
    end

    subgraph Unboxing
        E[Integer object holding 42] --> F{Context needs a primitive?<br/>e.g. int x = myInteger};
        F -- Yes --> G[Java automatically extracts<br/>the primitive value];
        G --> H[primitive int value 42];
    end
This diagram shows the processes of autoboxing and unboxing in Java. The top half, labeled "Autoboxing," illustrates a primitive int being automatically converted into an Integer object when the context requires it. The bottom half, "Unboxing," shows an Integer object being automatically converted back into a primitive int.

Core explanation

Hello everyone, it's Saavi. Today we're tackling a topic that bridges the gap between the simple data we've used so far and the powerful data structures we need for AP-level problems.

Primitives vs. Objects: The "Why"

Let's quickly review. In Java, we have two main kinds of data:

  • Primitives
    These are the simple, fundamental values. Think int, double, boolean. They hold a single value and nothing else. They're like a single, raw ingredient, like a cup of flour.
  • Objects
    These are more complex. They can hold data (instance variables) and have behaviors (methods). Think String, Scanner, or the ArrayLists we've been working with. They're like a finished cake—made of ingredients, but with its own structure and things you can do with it (like slice it).

Here's the problem that leads us to wrapper classes: ArrayList can only hold objects.

If you try to write this code, your program won't even compile:

// This code will NOT work!
ArrayList<int> myNumbers = new ArrayList<int>(); 

Java will give you an error because int is a primitive, not an object. It's like trying to put raw flour into a cake box that's only designed for finished cakes.

The Solution: Wrapper Classes

To solve this, Java provides wrapper classes. For every primitive type, there's a corresponding class that "wraps" it in an object. The two you absolutely must know for the AP exam are:

  • int -> Integer
  • double -> Double

Notice the capital letters—that's our clue that Integer and Double are classes, not primitives.

So, the correct way to declare an ArrayList for integers is:

// This is the correct way!
ArrayList<Integer> myNumbers = new ArrayList<Integer>();

Now, myNumbers is an ArrayList that can hold Integer objects.

Autoboxing and Unboxing: Java's Helping Hand

You might be thinking, "Great. So now every time I want to add a number, I have to manually create an Integer object? That sounds tedious."

Five years ago, you would have been right. You would have had to write: myNumbers.add(new Integer(10));

Thankfully, Java now does this for us automatically. This process is called autoboxing.

Autoboxing is the automatic conversion from a primitive type to its corresponding wrapper class object.

ArrayList<Integer> scores = new ArrayList<Integer>();

// Autoboxing in action!
// Java automatically converts the primitive int 100 into an Integer object.
scores.add(100); 

// It also works on assignment.
Integer myGrade = 95; // Java converts the int 95 to an Integer object.

The reverse process is called unboxing.

Unboxing is the automatic conversion from a wrapper class object back to its primitive type.

// Let's get the score back from our ArrayList.
// The .get() method returns an Integer object.
Integer scoreObject = scores.get(0); 

// Unboxing in action!
// Java automatically "unboxes" the Integer object into a primitive int.
int primitiveScore = scoreObject; 

// You can even do it directly in one line.
int myScore = scores.get(0); // .get(0) returns an Integer, which is unboxed to an int.

Think of it like this: Autoboxing is like putting a $10 bill into a gift card envelope. Unboxing is like taking the bill back out of the envelope to spend it. Java handles the envelope for you so you can just think about the money.

A Critical Detail: Immutability

Here's a concept that often trips students up. Integer and Double objects are immutable.

"Immutable" means that once the object is created, its internal value can never be changed.

Let's look at what seems like a contradiction:

Integer myAge = 25;
myAge = myAge + 1; // myAge is now 26

You might say, "Saavi, you just said it's immutable, but I just changed its value from 25 to 26!"

This is a fantastic observation, and it gets to the heart of how objects work. You didn't change the Integer object that held the value 25. Instead, Java did this behind the scenes:

  1. It unboxed myAge into a primitive int (25).
  2. It added 1 to that primitive int, resulting in 26.
  3. It autoboxed the result (26) into a brand new Integer object.
  4. It made the myAge variable point to this new object.

The original Integer object with the value 25 is now gone (garbage collected), and myAge refers to a completely different object. It's like signing a contract; you can't just cross out a term and change it. You have to void the old contract and write a whole new one.

Converting Strings to Numbers: parseInt and parseDouble

What if your data comes in as a String? For example, a user types their age into a text box on a website. You'll get the data as "25", not the number 25. You can't do math with a String!

The wrapper classes give us a tool for this. These are static methods, meaning you call them on the class itself, not an object.

  • Integer.parseInt(String s): Takes a string and returns a primitive int.
  • Double.parseDouble(String s): Takes a string and returns a primitive double.
String ageInput = "42";
String priceInput = "19.99";

// Convert the strings to primitive numbers
int age = Integer.parseInt(ageInput);
double price = Double.parseDouble(priceInput);

System.out.println("In ten years, you will be: " + (age + 10));
// Output: In ten years, you will be: 52

double priceWithTax = price * 1.0825; // Using a Dallas sales tax rate
System.out.println("Total price: " + priceWithTax);
// Output: Total price: 21.639175

See it in action

python
Line 1
Output
Click Run to see the output.

        
Try these
    © Shrutam.ai

    Worked examples

    Let's walk through a couple of problems to make these concepts concrete.

    Example 1

    Calculating the Average of Test Scores

    Problem: You are given a list of test scores for a class. Calculate the average score. The scores are stored in an ArrayList.

    Solution Walkthrough:

    1. 1
      Set up the Data
      First, we need an ArrayList to hold the scores. Since ArrayList can't hold primitive ints, we must use the Integer wrapper class.
      ArrayList<Integer> scores = new ArrayList<Integer>();
      scores.add(88); // Autoboxing: int -> Integer
      scores.add(92); // Autoboxing
      scores.add(77); // Autoboxing
      scores.add(100); // Autoboxing

      Why: We choose ArrayList<Integer> because it's the only way to store a list of integer numbers in an ArrayList. As we add the primitive int values, Java automatically converts them to Integer objects for us.

    2. 2
      Sum the Scores
      We need to iterate through the list and add up all the scores.
      int sum = 0;
      for (Integer score : scores) {
          sum = sum + score; // Unboxing here!
      }

      Why: Inside the loop, the variable score is an Integer object. When we write sum + score, Java sees that we're trying to do math with an object. It automatically unboxes the Integer object score into a primitive int so the addition can happen. This is the magic of unboxing in action.

    3. 3
      Calculate the Average
      Now that we have the sum, we can calculate the average. Remember, an average can have a decimal, so we should use a double.
      double average = (double) sum / scores.size();
      System.out.println("The average score is: " + average);
      // Output: The average score is: 89.25

      Why: We cast sum to a double before the division. If we didn't, we'd be doing integer division, which would chop off the decimal part and give us 89 instead of 89.25. This is a common mistake, but it's not related to wrapper classes—just good practice!

    Where students go wrong: They might try to declare the ArrayList as ArrayList<int>. Or, they might get confused about the sum = sum + score line, not realizing that unboxing is happening automatically. They know it works, but not why it works. Understanding the unboxing step is key.

    Example 2

    Processing Online Order Data

    Problem: You're processing data from an online form. You receive the quantity of an item as a String "3" and its price per item as a String "29.50". Calculate the total cost.

    Solution Walkthrough:

    1. 1
      Identify the Inputs
      We start with two String variables.
      String quantityStr = "3";
      String priceStr = "29.50";

      Why: This simulates getting data from a user or a file, which often comes in as text. We can't multiply "3" by "29.50".

    2. 2
      Convert Strings to Numbers
      We need to convert these strings into usable numeric types. We'll use the parse methods for this.
      int quantity = Integer.parseInt(quantityStr);
      double price = Double.parseDouble(priceStr);

      Why: Integer.parseInt() is the perfect tool for converting a string representation of a whole number into a primitive int. Double.parseDouble() does the same for a decimal number, converting it to a primitive double. We choose primitives here because our goal is simply to perform a calculation.

    3. 3
      Perform the Calculation
      Now that we have int and double primitives, we can do the math.
      double totalCost = quantity * price;
      System.out.println("Total cost: $" + totalCost);
      // Output: Total cost: $88.5

      Why: The calculation is straightforward once the data is in the correct numeric format.

    Where students go wrong: A common mistake is to confuse Integer.parseInt() with creating an Integer object. A student might write Integer quantity = Integer.parseInt(quantityStr);, which works due to autoboxing, but it's an unnecessary step. The goal of parseInt is to get a primitive int for calculations. Understanding that parseInt returns a primitive int simplifies your thinking.

    Try it yourself

    Ready to try it yourself? Take a shot at these.

    Problem 1: Sum of Even Numbers

    Write a method sumEvens that takes an ArrayList<Integer> as a parameter. The method should iterate through the list and return the sum of only the even numbers.

    public int sumEvens(ArrayList<Integer> numbers) {
        // Your code here
    }

    Problem 2: Gradebook from Text

    Write a method calculateAverage that takes an ArrayList<String> of grades (e.g., "95.5", "82.0", "76.8"). The method should calculate and return the average of these grades as a double.

    public double calculateAverage(ArrayList<String> gradeStrings) {
        // Your code here
    }