Java Wrapper Classes and Autoboxing

Wrapper classes represent primitive values as objects.

Lesson 45 of 127Intermediate14 min read

Wrapper classes represent primitive values as objects. Autoboxing converts a primitive to its wrapper, and unboxing extracts a primitive from that wrapper. These conversions make generic collections convenient, but null values and identity comparisons can create errors that ordinary int arithmetic does not have.

Review the related foundation lesson when you need a prerequisite. The complete programs below use Java 17-compatible syntax.

Primitive wrapper objects

Wrapper types such as Integer and Double represent primitive values as objects. Generics use reference types, so List<Integer> stores boxed integer values.

Java provides wrappers such as Integer for int, Long for long, Double for double and Boolean for boolean. Generic type arguments require reference types, so List<Integer> stores integer wrapper references while List<int> is invalid. Boxing can occur when adding an int to that list, and unboxing can occur when its element is used in arithmetic.

Boxing, unboxing and null

Autoboxing converts a primitive to its wrapper where needed; unboxing retrieves the primitive value. Unboxing null throws NullPointerException.

A wrapper reference can be null because it is an object reference. Unboxing null throws NullPointerException before the arithmetic or comparison can complete. Treat nullable data as an explicit possibility, especially when Map.get returns null for a missing key. A defaulting operation or presence check can resolve that case, but do not silently choose zero when missing and zero have different meanings.

Parsing numeric text

Integer.parseInt parses text into an int, while Integer.valueOf supplies an Integer. Malformed numeric text throws NumberFormatException.

parseInt converts numeric text to a primitive int, while Integer.valueOf returns an Integer wrapper. Invalid text and out-of-range numbers produce NumberFormatException. Wrapper values are immutable: incrementing an Integer variable unboxes, computes and assigns a new boxed result rather than mutating the original wrapper. That distinction is useful when several references initially share one value.

Value equality versus identity

Use equals for wrapper value comparison. Reference == can appear to work for some cached Integer values but is not a dependable general numeric comparison.

Comparing two wrapper references with == tests identity unless the expression requires unboxing. Some wrapper values are cached, so equal small values can unexpectedly compare identical while other equal values do not. Use equals for wrapper content equality, or compare deliberately unboxed primitives when null has already been ruled out. Never base application equality on cache behavior.

Running the examples

Save name.java, compile it with javac --release 17 name.java, and run java name. Use each program's own public class name and filename.

How BoxedDonations produces its output

List.of receives three numeric arguments that become Integer elements. Each loop iteration unboxes its amount when adding to the primitive total. Fourteen plus eight plus eleven produces thirty-three, so the output is Seeds: 33. The list has no null elements; a null Integer in a different source would fail during that same unboxing step.

How BoxedScores produces its output

Adding twelve boxes the primitive into an Integer suitable for the list's reference-type element contract. get returns an Integer, and multiplication unboxes it to an int. The doubled primitive becomes twenty-four. The conversion is convenient but still depends on retrieving a non-null wrapper.

How WrapperEquality produces its output

Both parsing operations produce wrappers containing one thousand. equals compares those numeric contents without relying on reference identity or caching. Objects.equals safely compares a non-null value with null and returns false. Calling first.equals is safe here because first is non-null; calling missing.equals would instead fail before a comparison.

Handle absent boxed values at the lookup boundary

A map from names to Integer counts can return null for a missing name. Calling get and immediately adding one asks Java to unbox that missing reference, which fails before a useful update occurs. Use a documented default only if an absent count really means zero, or reject missing data when that is the correct contract. getOrDefault does not replace an explicitly stored null value, so a map that permits both absence and null needs more careful handling. For practice, compare a missing key, a key mapped to zero and a key mapped to null. Explain their meanings before choosing an arithmetic operation.

Equal-looking numbers can have different wrapper types

Integer.valueOf(4).equals(Long.valueOf(4)) is false because Integer.equals requires another Integer with the same value. The two objects represent numbers that look equal in decimal output, but wrapper equality is not a universal cross-type numeric comparison. Choose the intended numeric representation before comparing values from different sources. Converting through double can lose precision for large integers, while converting through int can truncate values outside its range. parseInt also differs from silently narrowing a long: it rejects an out-of-range decimal string. Understanding those boundaries is especially useful when an API returns Number and the application must decide which concrete numeric types it accepts.

Java Summary

  • Wrapper types such as Integer and Double represent primitive values as objects. Generics use reference types, so List<Integer> stores boxed integer values.
  • Autoboxing converts a primitive to its wrapper where needed; unboxing retrieves the primitive value. Unboxing null throws NullPointerException.
  • Integer.parseInt parses text into an int, while Integer.valueOf supplies an Integer. Malformed numeric text throws NumberFormatException.
  • Use equals for wrapper value comparison. Reference == can appear to work for some cached Integer values but is not a dependable general numeric comparison.
  • Continue with Java exercises, Java quizzes and the Java study roadmap.

Java Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Java Wrapper Classes and Autoboxing in a complete program

Java
public class BoxedDonations  {
    public static void main(String[] args)  {
        java.util.List<Integer> donations = java.util.List.of(14, 8, 11);
        int total = 0;
        for (Integer amount : donations) total += amount;
        System.out.println("Seeds: " + total);
    }
}
Output
Seeds: 33
Line-by-line explanation
  1. Line 6Evaluates "Seeds: " + total and prints Seeds: 33.
Example 2

Boxing supports generic lists

Java
public class BoxedScores  {
    public static void main(String[] args)  {
        java.util.List<Integer> scores = new java.util.ArrayList<>();
        scores.add(12);
        int doubled = scores.get(0) * 2;
        System.out.println(doubled);
    }
}
Output
24
Line-by-line explanation
  1. Line 6Evaluates doubled and prints 24.
Example 3

Wrapper content equality is explicit

Java
public class WrapperEquality  {
    public static void main(String[] args)  {
        Integer first = Integer.valueOf("1000");
        Integer second = Integer.valueOf("1000");
        System.out.println(first.equals(second));
        Integer missing = null;
        System.out.println(java.util.Objects.equals(first, missing));
    }
}
Output
true
false
Line-by-line explanation
  1. Line 5Evaluates first.equals(second) and prints true.
  2. Line 7Evaluates java.util.Objects.equals(first, missing) and prints false.

Java FAQ

Is an Integer mutable?

No. An expression such as count++ computes a new numeric value and reassigns the variable through unboxing and boxing. It does not change an Integer object shared by other references. The variable and the object it currently refers to are separate.

When should I prefer primitives?

Use primitives for ordinary non-null arithmetic and storage when object semantics are unnecessary. Use wrappers for generic collections, nullable values or APIs that require reference types. Decide whether null is meaningful before selecting a wrapper solely for convenience.

Why does == work for Integer 127 but not 128?

Integer.valueOf, which autoboxing uses, reuses cached objects for values from -128 to 127. Two boxed 127s are therefore the same object and == returns true, while two boxed 128s are separate objects and == returns false. Always compare wrapper values with equals() or unbox them first.

Do wrapper objects use more memory than primitives?

Yes. An int takes 4 bytes, while an Integer is a full object with a header, typically about 16 bytes, plus the reference that points to it. That rarely matters for a few values, but for millions of numbers an int[] or IntStream is far more compact than a List<Integer>.

Can an Integer be assigned to a Long variable?

No. Java widens primitives automatically, so long n = 4; works, but it doesn't convert between wrapper classes: Long l = Integer.valueOf(4); is a compile error. Convert explicitly with Long.valueOf(i.longValue()), or unbox into a primitive long first.

Java Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choiceeasy

What happens when a null Integer is used in addition?

Multiple choicemedium

Which generic element declaration is valid?

Java Quiz

2 questions to check what you learned.

  1. How should two non-null Integer contents be compared?

    • With equals
    • By assuming == always compares numeric content
    • By comparing their source filenames
  2. What does Integer.parseInt return?

    • A primitive int
    • An Integer array
    • A nullable String