00:00

Wrapper Classes in Java – Autoboxing, Unboxing and Conversions

Last updated: 5 min read

A wrapper class wraps a primitive value in an object. Java has one wrapper for each of its eight primitive types, such as Integer for int and Double for double. Wrappers are needed wherever objects are required, most importantly in collections and generics (List<Integer>, not List<int>), and they provide useful constants and conversion methods.

This tutorial covers the eight wrapper classes, autoboxing and unboxing, parsing and conversion methods, the Integer cache and the pitfalls of comparing wrappers and unboxing null.

1. Primitive Types and Their Wrappers

PrimitiveWrapper classCached values (valueOf)
byteByteAll (−128 to 127)
shortShort−128 to 127
intInteger−128 to 127 (upper bound configurable)
longLong−128 to 127
floatFloatNone
doubleDoubleNone
charCharacter0 to 127
booleanBooleanTRUE and FALSE

All wrappers are in java.lang, are immutable and final. The numeric ones extend the abstract class Number.

2. Autoboxing and Unboxing

Since Java 5 the compiler converts automatically between primitives and wrappers: autoboxing (primitive → wrapper) and unboxing (wrapper → primitive):

Autoboxing.java
import java.util.ArrayList;
import java.util.List;

public class Autoboxing {
    public static void main(String[] args) {
        Integer boxed = Integer.valueOf(42);   // explicit boxing
        int raw = boxed.intValue();            // explicit unboxing

        Integer auto = 7;                      // autoboxing: compiler calls Integer.valueOf(7)
        int sum = auto + 3;                    // auto-unboxing: auto.intValue() + 3
        System.out.println(raw + " " + sum);

        List<Integer> scores = new ArrayList<>();   // collections need objects
        scores.add(90);                              // autoboxed
        scores.add(85);
        int total = 0;
        for (int s : scores) total += s;            // unboxed
        System.out.println("total = " + total);
    }
}
Output
42 10
total = 175

Boxing creates objects, so in performance-critical loops prefer primitives, primitive arrays or primitive streams such as IntStream.

3. Parsing and Conversion Methods

ConversionMethods.java
public class ConversionMethods {
    public static void main(String[] args) {
        int a = Integer.parseInt("123");                 // String -> primitive
        Integer b = Integer.valueOf("456");              // String -> wrapper
        double d = Double.parseDouble("3.75");
        boolean flag = Boolean.parseBoolean("TRUE");     // case-insensitive "true"
        System.out.println(a + b + " " + d + " " + flag);

        System.out.println(Integer.toString(255) + " " + String.valueOf(9.5));   // to String
        System.out.println("binary: " + Integer.toBinaryString(10) + ", hex: " + Integer.toHexString(255)
                           + ", parse hex: " + Integer.parseInt("ff", 16));
        System.out.println("MAX: " + Integer.MAX_VALUE + ", MIN: " + Integer.MIN_VALUE + ", BYTES: " + Integer.BYTES);
        System.out.println("compare(5, 9): " + Integer.compare(5, 9) + ", max: " + Integer.max(5, 9) + ", sum: " + Integer.sum(5, 9));
        System.out.println("isDigit('7'): " + Character.isDigit('7') + ", toUpperCase('j'): " + Character.toUpperCase('j'));

        try {
            Integer.parseInt("12a");
        } catch (NumberFormatException e) {
            System.out.println(e.getMessage());
        }
    }
}
Output
579 3.75 true
255 9.5
binary: 1010, hex: ff, parse hex: 255
MAX: 2147483647, MIN: -2147483648, BYTES: 4
compare(5, 9): -1, max: 9, sum: 14
isDigit('7'): true, toUpperCase('j'): J
For input string: "12a"
MethodReturnsExample
parseXxx(String)PrimitiveInteger.parseInt("42")
valueOf(String / primitive)Wrapper (uses the cache)Integer.valueOf(42)
xxxValue()Primitivenum.doubleValue()
toString(primitive)StringInteger.toString(42)
compare, max, min, sumint / primitiveInteger.compare(a, b)

Invalid text throws NumberFormatException, so validate or catch it when parsing user input. The wrapper constructors (new Integer(5)) are deprecated for removal; use valueOf or autoboxing.

4. The Integer Cache and Comparing Wrappers

IntegerCache.java
public class IntegerCache {
    public static void main(String[] args) {
        Integer a = 127, b = 127;      // cached range -128..127: same object
        Integer c = 128, d = 128;      // outside the cache: different objects
        System.out.println("127 == 127 : " + (a == b));
        System.out.println("128 == 128 : " + (c == d));
        System.out.println("128 equals : " + c.equals(d));     // always compare with equals()

        Long l = 10L;
        Integer i = 10;
        System.out.println("Long(10).equals(Integer(10)): " + l.equals(i));   // different types!
    }
}
Output
127 == 127 : true
128 == 128 : false
128 equals : true
Long(10).equals(Integer(10)): false

Integer.valueOf (and therefore autoboxing) returns cached objects for −128 to 127, so == happens to work for small numbers and fails for larger ones. Always compare wrapper values with equals() (or unbox to primitives). Note that equals also checks the type: a Long never equals an Integer.

5. Unboxing null

A wrapper variable can be null; a primitive cannot. Unboxing null throws NullPointerException, a common bug with maps:

UnboxingNull.java
import java.util.HashMap;
import java.util.Map;

public class UnboxingNull {
    public static void main(String[] args) {
        Map<String, Integer> stock = new HashMap<>();
        stock.put("pen", 10);

        Integer missing = stock.get("pencil");          // null: no such key
        System.out.println("missing = " + missing);
        try {
            int count = stock.get("pencil");            // auto-unboxing null -> NullPointerException
        } catch (NullPointerException e) {
            System.out.println("NullPointerException when unboxing null");
        }
        int safe = stock.getOrDefault("pencil", 0);     // avoid it
        System.out.println("safe = " + safe);
    }
}
Output
missing = null
NullPointerException when unboxing null
safe = 0

6. Primitive or Wrapper?

Use a primitive when…Use a wrapper when…
Doing calculations, loops and countersStoring values in collections or generics
Performance and memory matterA value may be absent (null), such as an optional database column
Default value 0/false is meaningfulYou need utility methods or reflection-based frameworks require objects

7. Summary

  • Each primitive has an immutable wrapper class in java.lang.
  • Autoboxing and unboxing convert automatically between primitives and wrappers.
  • Use parseXxx for primitives and valueOf for wrappers; watch for NumberFormatException.
  • Compare wrappers with equals(), not ==, because of caching.
  • Unboxing null throws NullPointerException.

Related Tutorials