Wrapper Classes
BeginnerUse the eight wrapper classes to treat primitives as objects, leverage autoboxing, and unlock the rich utility methods on Integer, Double, and friends.
Overview
Every primitive type in Java has a corresponding wrapper class: byte→Byte, short→Short, int→Integer, long→Long, float→Float, double→Double, char→Character, boolean→Boolean. Wrappers let primitives participate in collections (List<Integer>), generics, and null-safe code. Autoboxing and unboxing (Java 5+) convert automatically between primitive and wrapper. Each wrapper also ships with parsing methods (Integer.parseInt), conversion methods, and MIN_VALUE/MAX_VALUE constants.
Wrapper Hierarchy & Key Constants
All numeric wrappers extend the abstract Number class, which defines intValue(), longValue(), floatValue(), doubleValue(), byteValue(), and shortValue() — allowing you to convert any Number to any numeric primitive.
The most-used constants and factory methods: Integer.MAX_VALUE / MIN_VALUE — 2³¹−1 / −2³¹ Integer.parseInt(str) — String → int (throws NumberFormatException) Integer.valueOf(int) — int → Integer (uses cache for −128..127) Integer.toString(int) / Integer.toBinaryString(int) / toHexString / toOctalString Integer.bitCount(n) — number of set bits Math class complements wrappers for math operations.
public class WrapperConstants {
public static void main(String[] args) {
// Range constants
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648
System.out.println(Long.MAX_VALUE); // 9223372036854775807
System.out.println(Double.MAX_VALUE); // 1.7976931348623157E308
// Parsing — String → primitive
int i = Integer.parseInt("42");
long l = Long.parseLong("9876543210");
double d = Double.parseDouble("3.14");
boolean b = Boolean.parseBoolean("true"); // case-insensitive
System.out.println(i + " " + l + " " + d + " " + b);
// Conversion methods
System.out.println(Integer.toBinaryString(255)); // 11111111
System.out.println(Integer.toHexString(255)); // ff
System.out.println(Integer.toOctalString(8)); // 10
System.out.println(Integer.bitCount(255)); // 8
System.out.println(Integer.reverse(1)); // MSB becomes LSB
// Number hierarchy — any Number can give any numeric primitive
Number n = 3.7; // Double is-a Number
System.out.println(n.intValue()); // 3 (truncates)
System.out.println(n.longValue()); // 3
System.out.println(n.doubleValue()); // 3.7
// Character utilities
System.out.println(Character.isDigit('5')); // true
System.out.println(Character.isLetter('A')); // true
System.out.println(Character.toLowerCase('Z')); // z
System.out.println(Character.isWhitespace(' ')); // true
}
}Autoboxing, Unboxing & the Integer Cache
Autoboxing: primitive → wrapper (happens automatically when assigning to a wrapper type or adding to a collection). Unboxing: wrapper → primitive (happens automatically when using a wrapper in arithmetic or assigning to a primitive).
The Integer cache stores pre-created Integer objects for values −128 to 127. Integer.valueOf(n) returns the cached instance in this range, so == works. Outside this range, new objects are created on every valueOf() call. This is why == fails for Integer values > 127 — always use .equals() for wrapper comparison.
Unboxing a null wrapper throws NullPointerException — a common subtle bug.
import java.util.ArrayList;
import java.util.List;
public class AutoboxingDemo {
public static void main(String[] args) {
// Autoboxing: int → Integer
Integer a = 42; // equivalent to Integer.valueOf(42)
int b = a; // unboxing: Integer → int
// Integer cache: -128 to 127
Integer x = 100, y = 100;
System.out.println(x == y); // true — same cached object
Integer p = 200, q = 200;
System.out.println(p == q); // false — different objects
System.out.println(p.equals(q)); // true — always use equals()
// Unboxing null → NullPointerException
Integer nullInt = null;
try {
int val = nullInt; // unboxing null!
} catch (NullPointerException e) {
System.out.println("NPE from unboxing null wrapper");
}
// Performance: autoboxing inside loops is costly
long sum = 0;
List<Integer> numbers = new ArrayList<>();
for (int i = 0; i < 100; i++) numbers.add(i); // 100 autobox operations
// Prefer primitive streams for numeric aggregation
sum = numbers.stream().mapToLong(Integer::longValue).sum();
System.out.println(sum); // 4950
// Comparing wrappers safely
Integer m = 500, n = 500;
System.out.println(Integer.compare(m, n)); // 0 (equal)
System.out.println(m.compareTo(n)); // 0
}
}Optional Parsing & Null Safety
Integer.parseInt() throws NumberFormatException on invalid input. For user input or external data where the value might not be a number, wrap the parse in a try-catch or write a helper that returns Optional<Integer>.
Java 11+ added some convenience: use Objects.requireNonNullElse() for null coalescing. For number formatting, use NumberFormat or String.format rather than manual string building.
import java.util.Optional;
import java.util.Objects;
import java.text.NumberFormat;
import java.util.Locale;
public class SafeParsing {
// Safe parse — returns Optional instead of throwing
static Optional<Integer> tryParseInt(String s) {
try {
return Optional.of(Integer.parseInt(s.trim()));
} catch (NumberFormatException e) {
return Optional.empty();
}
}
public static void main(String[] args) {
// Safe parsing
tryParseInt("42").ifPresent(n -> System.out.println("Parsed: " + n));
tryParseInt("abc").ifPresentOrElse(
n -> System.out.println("Parsed: " + n),
() -> System.out.println("Not a valid number")
);
// Null-safe default with Objects.requireNonNullElse
Integer value = null;
int result = Objects.requireNonNullElse(value, 0);
System.out.println(result); // 0
// Number formatting
NumberFormat fmt = NumberFormat.getNumberInstance(Locale.US);
System.out.println(fmt.format(1_234_567.89)); // 1,234,567.89
// Currency
NumberFormat curr = NumberFormat.getCurrencyInstance(Locale.US);
System.out.println(curr.format(9.99)); // $9.99
// Wrapper comparisons
System.out.println(Integer.max(10, 20)); // 20
System.out.println(Integer.min(10, 20)); // 10
System.out.println(Integer.sum(10, 20)); // 30 — useful as method ref
}
}Key Points to Remember
- All numeric wrappers extend Number — intValue(), doubleValue() etc. convert between types
- Integer cache covers −128 to 127: use .equals() for all wrapper comparisons, never ==
- Unboxing a null wrapper throws NullPointerException — guard with null checks or Optional
- parseInt() vs valueOf(): parseInt returns a primitive; valueOf returns a (possibly cached) wrapper
- Autoboxing in tight loops is costly — use primitive arrays or streams for numeric aggregation
- Character has rich utility: isDigit(), isLetter(), isWhitespace(), toUpperCase(), toLowerCase()
Practice Wrapper Classes in the Playground
Run and modify code directly in your browser - no setup needed.
Interview Questions
Sign in to ask AriaWhy does Integer == Integer return false for values outside −128 to 127?
What is the difference between Integer.parseInt() and Integer.valueOf()?
What happens when you unbox a null Integer?
What is autoboxing? What are its performance implications?
Which class do all numeric wrapper classes extend?
Ask Aria about Wrapper Classes
Your personal AI tutor — ask anything about this concept