Getting Started
In Java, we often distinguish between primitive types (like int and double) and object types (like String or custom classes). Data structures like ArrayList are designed to store collections of objects only. This presents a problem: how can we store a list of integers or decimal numbers? Wrapper classes provide the solution by "wrapping" a primitive value inside an object, making it compatible with ArrayList and other object-oriented features of Java.
What You Should Be Able to Do
Explain why wrapper classes are necessary for use with collections like
ArrayList.Declare and initialize an
ArrayListthat storesIntegerorDoubleobjects.Describe the automatic processes of autoboxing (primitive to wrapper object) and unboxing (wrapper object to primitive).
Use the
Integerclass constantsMIN_VALUEandMAX_VALUEto represent the bounds of theintdata type.Write code that correctly adds primitive values to an
ArrayListof a wrapper type and retrieves them.
Key Concepts & Java Implementation
The Core Idea
A primitive type is a fundamental data type in Java that stores a single, simple value directly in memory. Examples include int, double, and boolean. An object, on the other hand, is an instance of a class, a more complex structure that bundles data (instance variables) and behaviors (methods) together.
The ArrayList class is designed to be a flexible container that can hold any kind of object. However, its internal structure is built to handle references to objects, not primitive values. Therefore, you cannot create an ArrayList of a primitive type, like int.
// This line of code will cause a compile-time error.
ArrayList<int> numberList = new ArrayList<int>();
To solve this, Java provides a wrapper class for each primitive type. A wrapper class is a class that encapsulates, or "wraps," a single primitive value inside an object. This allows us to treat a primitive value as if it were an object, making it compatible with ArrayList. The two most common wrapper classes you will use are Integer (for int) and Double (for double).
Syntax & Implementation
Java simplifies the use of wrapper classes with two automatic processes: autoboxing and unboxing.
Autoboxing: The automatic conversion that the Java compiler makes between a primitive type and its corresponding wrapper class object. When you try to add an
intto anArrayList<Integer>, Java automatically "boxes" theintinto a newIntegerobject for you.Unboxing: The automatic conversion that the Java compiler makes from a wrapper class object back to its corresponding primitive type. When you retrieve an
Integerobject from anArrayListand assign it to anintvariable, Java automatically "unboxes" the value for you.
Syntax Table: Common Wrapper Classes
| Primitive Type | Wrapper Class | Java Declaration Example |
|---|---|---|
int | Integer | ArrayList<Integer> scores = new ArrayList<>(); |
double | Double | ArrayList<Double> prices = new ArrayList<>(); |
Annotated Java Examples
The following example demonstrates creating an ArrayList of Integer objects and leveraging autoboxing and unboxing.
import java.util.ArrayList;
public class ScoreTracker {
public static void main(String[] args) {
// 1. Declare and initialize an ArrayList to hold Integer objects.
ArrayList<Integer> scores = new ArrayList<>();
// 2. Add primitive int values. Autoboxing handles the conversion.
scores.add(95); // Java converts int 95 to an Integer object
scores.add(88); // Java converts int 88 to an Integer object
scores.add(72); // Java converts int 72 to an Integer object
System.out.println("Scores in list: " + scores);
// 3. Retrieve a value and perform a calculation. Unboxing handles the conversion.
int firstScore = scores.get(0); // Java converts the Integer object at index 0 to an int
int total = 0;
// 4. Use a for-each loop, which also uses unboxing.
for (Integer currentScore : scores) {
// The 'currentScore' Integer object is unboxed to an int for the addition.
total += currentScore;
}
System.out.println("First score: " + firstScore);
System.out.println("Total of all scores: " + total);
}
}
Output of the code:
Scores in list: [95, 88, 72]
First score: 95
Total of all scores: 255
The Integer class also provides useful constants, MIN_VALUE and MAX_VALUE, which hold the smallest and largest possible values for the int data type.
public class IntegerBounds {
public static void main(String[] args) {
// These are public static final constants of the Integer class.
int smallestInt = Integer.MIN_VALUE;
int largestInt = Integer.MAX_VALUE;
System.out.println("The smallest possible int is: " + smallestInt);
System.out.println("The largest possible int is: " + largestInt);
}
}
Output of the code:
The smallest possible int is: -2147483648
The largest possible int is: 2147483647
Tracing & Analysis
Let's trace the execution of adding and retrieving values from an ArrayList<Integer>.
Code to Trace:
ArrayList<Integer> list = new ArrayList<>();
list.add(10);
list.add(20);
int x = list.get(0);
int y = list.get(1);
int sum = x + y;
Execution Trace:
| Line of Code | list (State) | x (Value) | y (Value) | sum (Value) | Notes |
|---|---|---|---|---|---|
ArrayList<Integer> list = new ArrayList<>(); | [] (empty) | uninitialized | uninitialized | uninitialized | An empty ArrayList of Integer objects is created. |
list.add(10); | [10] | uninitialized | uninitialized | uninitialized | Autoboxing: int 10 is converted to an Integer object and added. |
list.add(20); | [10, 20] | uninitialized | uninitialized | uninitialized | Autoboxing: int 20 is converted to an Integer object and added. |
int x = list.get(0); | [10, 20] | 10 | uninitialized | uninitialized | Unboxing: The Integer object at index 0 is converted to int 10. |
int y = list.get(1); | [10, 20] | 10 | 20 | uninitialized | Unboxing: The Integer object at index 1 is converted to int 20. |
int sum = x + y; | [10, 20] | 10 | 20 | 30 | The two primitive int values are added. |
Analysis:
While autoboxing and unboxing are extremely convenient, it is crucial to remember that they are not "magic." The compiler is generating code to create new objects (Integer or Double) and to call methods to extract their primitive values. This is a seamless process, but understanding the underlying object creation and method calls is key to mastering how Java manages data.
Java Syntax Quick-Reference
Integer: The wrapper class for theintprimitive type. Used for storing integer values in object-based collections likeArrayList.Double: The wrapper class for thedoubleprimitive type. Used for storing floating-point values in object-based collections.Integer.MIN_VALUE: Apublic static final intconstant that holds the minimum value anintcan represent (-231).Integer.MAX_VALUE: Apublic static final intconstant that holds the maximum value anintcan represent (231 - 1).
Core Code Examples & Terminology
Primitive Type: A fundamental data type that is not an object and stores a value directly in memory, such as
int,double, orboolean.Wrapper Class: A class that encapsulates a primitive data type within an object, allowing the primitive to be used in contexts that require objects (e.g.,
ArrayList).Autoboxing: The automatic conversion of a primitive value into an instance of its corresponding wrapper class (e.g.,
inttoInteger).Unboxing: The automatic conversion of a wrapper class object back into its corresponding primitive value (e.g.,
Integertoint).Declaring an
ArrayListfor Integers:ArrayList<Integer> studentAges = new ArrayList<>();This code creates an empty list that is specifically typed to hold
Integerobjects.Using Autoboxing:
ArrayList<Integer> numbers = new ArrayList<>(); numbers.add(42); // The int 42 is autoboxed into an Integer object.This code demonstrates adding a primitive
intdirectly to anArrayList<Integer>, relying on the compiler to perform the conversion.Using Unboxing:
int myNum = numbers.get(0); // The Integer object is unboxed into an int.This code retrieves an
Integerobject from the list and assigns its value to a primitiveintvariable, relying on unboxing.
Core Skill Check
Code Tracing: What is the final value of
sumafter this Java code runs:ArrayList<Integer> vals = new ArrayList<>(); vals.add(5); vals.add(12); int sum = vals.get(0) + vals.get(1);?- Answer:
17
- Answer:
Debugging: Identify the compile-time error in this Java code:
ArrayList<double> measurements = new ArrayList<>();.- Answer: The type parameter for
ArrayListcannot be a primitive type (double). It must be a class name, such as its wrapper classDouble.
- Answer: The type parameter for
Application: Write a single line of Java code that adds the integer
100to an existingArrayList<Integer>namedhighScores.- Answer:
highScores.add(100);
- Answer:
Common Misconceptions & Errors
Using Primitives with
ArrayList: A common mistake is trying to declare anArrayListwith a primitive type, likeArrayList<int>. This will always cause a compile-time error because generic type parameters must be object types. Always use the wrapper class (Integer,Double, etc.).Confusing
intandInteger: While autoboxing makes them seem interchangeable, they are different.intis a primitive value.Integeris an object that holds anintvalue. AnIntegervariable can also benull, which can lead to aNullPointerExceptionif you try to unbox it.Forgetting Unboxing Occurs: When performing arithmetic with a wrapper object (e.g.,
Integer num = 5; int result = num * 2;), remember that theIntegernumis first unboxed to a primitiveintbefore the multiplication can happen.
Summary
Wrapper classes bridge the gap between Java's primitive types and its object-oriented data structures. Because collections like ArrayList can only store objects, we use wrapper classes like Integer and Double to contain primitive int and double values. The Java compiler makes this process seamless through autoboxing (automatically converting a primitive to a wrapper object) and unboxing (automatically converting a wrapper object back to a primitive). This allows you to write clean, readable code that treats primitive values and objects in a unified way within collections.