Wrapper Classes
Java’s primitive types (int, double, boolean, etc.) are fast and memory-efficient, but there are situations where you need an object — for example, when storing values in a collection like ArrayList. Wrapper classes solve this by wrapping each primitive type in a corresponding class that lives in java.lang.
What Are Wrapper Classes?
Every primitive type in Java has a matching wrapper class. The wrapper acts as a box around the raw value, turning it into a full-fledged object with methods you can call.
| Primitive | Wrapper Class |
|---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
All numeric wrapper classes extend Number, which is worth knowing when you work with generic numeric code.
Creating Wrapper Objects
Since Java 9, the constructors (new Integer(42)) are deprecated. Use the static factory method valueOf() instead — it is more efficient because it can return a cached instance.
Integer a = Integer.valueOf(42);
Double b = Double.valueOf(3.14);
Boolean c = Boolean.valueOf(true);
Character d = Character.valueOf('Z');
System.out.println(a); // 42
System.out.println(b); // 3.14
System.out.println(c); // true
System.out.println(d); // Z
Output:
42
3.14
true
Z
Autoboxing and Unboxing
Since Java 5 the compiler handles conversions between primitives and wrappers automatically. This feature is called autoboxing (primitive → wrapper) and unboxing (wrapper → primitive).
// Autoboxing: int is automatically wrapped into Integer
Integer x = 100;
// Unboxing: Integer is automatically unwrapped back to int
int y = x;
System.out.println(x + " " + y); // 100 100
Output:
100 100
Autoboxing makes it natural to put primitives into collections:
import java.util.ArrayList;
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(10); // autoboxed to Integer.valueOf(10)
numbers.add(20);
numbers.add(30);
int sum = 0;
for (int n : numbers) { // unboxed automatically
sum += n;
}
System.out.println("Sum: " + sum);
Output:
Sum: 60
Note: Without wrapper classes,
ArrayList<int>would be a compile error — generics only work with reference types, not primitives. For high-performance use cases, consider primitive-specialized collections from libraries like Eclipse Collections.
Parsing Strings to Primitives
One of the most common reasons to reach for a wrapper class is parsing user input or text data into numbers.
String ageText = "25";
String priceText = "9.99";
String flagText = "true";
int age = Integer.parseInt(ageText);
double price = Double.parseDouble(priceText);
boolean flag = Boolean.parseBoolean(flagText);
System.out.println(age + 1); // 26
System.out.println(price * 2); // 19.98
System.out.println(!flag); // false
Output:
26
19.98
false
Warning:
Integer.parseInt("abc")throws aNumberFormatExceptionat runtime. Always validate input or wrap the call in a try-catch. See Exception Handling for patterns.
Converting Numbers to Strings
The reverse direction is equally easy:
int n = 42;
String s1 = Integer.toString(n); // "42"
String s2 = String.valueOf(n); // "42" (works for any primitive)
String s3 = "" + n; // "42" via concatenation
System.out.println(s1 + " " + s2 + " " + s3);
Output:
42 42 42
Useful Utility Methods
Each wrapper class ships with a rich set of static utility methods. Here are some you’ll reach for regularly:
Integer Utilities
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648
System.out.println(Integer.toBinaryString(10)); // 1010
System.out.println(Integer.toHexString(255)); // ff
System.out.println(Integer.toOctalString(8)); // 10
System.out.println(Integer.bitCount(7)); // 3 (bits set in 0b111)
System.out.println(Integer.reverse(1)); // large number (bit reversal)
System.out.println(Integer.compare(5, 10)); // negative (5 < 10)
Character Utilities
char ch = 'A';
System.out.println(Character.isLetter(ch)); // true
System.out.println(Character.isDigit(ch)); // false
System.out.println(Character.isUpperCase(ch)); // true
System.out.println(Character.toLowerCase(ch)); // a
System.out.println(Character.isWhitespace(' ')); // true
Double Utilities
System.out.println(Double.isNaN(0.0 / 0.0)); // true
System.out.println(Double.isInfinite(1.0 / 0.0)); // true
System.out.println(Double.MAX_VALUE); // 1.7976931348623157E308
Comparing Wrapper Objects
Warning: Never use
==to compare wrapper objects — it checks reference equality, not value equality. ForIntegervalues between −128 and 127 it might appear to work (due to the integer cache), but it will silently fail for values outside that range.
Integer p = 1000;
Integer q = 1000;
System.out.println(p == q); // false — different objects
System.out.println(p.equals(q)); // true — same value
System.out.println(Integer.compare(p, q)); // 0 — equal
Always use .equals() or the static Integer.compare() / Comparator.naturalOrder() methods when comparing wrapper values. This is especially important when sorting — see Comparator.
Null Handling — a Gotcha with Unboxing
Because wrapper objects are reference types, they can be null. Unboxing a null wrapper throws a NullPointerException.
Integer value = null;
int result = value; // NullPointerException at runtime!
Guard against this wherever nullable wrappers flow through your code:
Integer value = null;
int result = (value != null) ? value : 0;
System.out.println(result); // 0
Optional from Java 8 is another clean way to handle the possibility of an absent value.
Under the Hood
Integer Cache
The JVM caches Integer objects for values between −128 and 127 (configurable up to 127+ via -XX:AutoBoxCacheMax). Calls to Integer.valueOf(n) within this range return the same cached object. That’s why Integer.valueOf(100) == Integer.valueOf(100) is true but Integer.valueOf(1000) == Integer.valueOf(1000) is false. Byte, Short, Long, and Character (0–127) have similar caches.
Memory Cost
A boxed Integer on the heap takes around 16 bytes (object header) plus 4 bytes for the int field — roughly 5× the cost of a plain int. In tight loops or large arrays this overhead adds up. That’s why Java has kept primitives in the language, and why Java 21 features (Project Valhalla, moving toward value types) aim to close this gap.
Bytecode
When the compiler sees autoboxing, it silently inserts a invokestatic Integer.valueOf(I)Ljava/lang/Integer; call. Unboxing becomes invokevirtual Integer.intValue()I. You can verify this with the javap tool:
// Source: Integer x = 5;
0: iconst_5
1: invokestatic #2 // Method Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_1
Understanding this helps you write performance-conscious code — unnecessary boxing in hot loops is a real (though often avoidable) cost.
Immutability
All wrapper objects are immutable. Once created, the value inside cannot change. This makes them safe to share across threads without synchronisation, and is also why the integer cache is sound. If you need a mutable counter in concurrent code, look at java.util.concurrent.atomic.AtomicInteger instead.
Quick Reference
// Parse
int i = Integer.parseInt("123");
long l = Long.parseLong("9876543210");
double d = Double.parseDouble("3.14");
// Convert to String
String s = Integer.toString(42);
String h = Integer.toHexString(255); // "ff"
String b = Integer.toBinaryString(5); // "101"
// Limits
int max = Integer.MAX_VALUE; // 2_147_483_647
long lmax = Long.MAX_VALUE;
// Check special values
boolean nan = Double.isNaN(Double.NaN);
boolean inf = Double.isInfinite(1.0 / 0.0);
// Character checks
boolean isLetter = Character.isLetter('a');
char upper = Character.toUpperCase('z'); // 'Z'
Related Topics
- Autoboxing & Unboxing — a deeper look at the compiler magic behind primitive-to-object conversions
- Generics — why type parameters require reference types and how wrapper classes make collections type-safe
- ArrayList — the most common place you’ll rely on wrapper classes in everyday code
- Data Types — the primitive types that each wrapper class corresponds to
- Optional — a modern alternative to nullable wrappers when a value might be absent
- Comparable — wrapper classes implement
Comparable, enabling natural ordering in sorted collections