Each primitive has an immutable wrapper class so it can live where objects are required (collections, generics, null). The compiler converts between them automatically — sometimes with surprising results.
| Primitive | Wrapper | Cache (valueOf) |
|---|---|---|
byte | Byte | all values |
short | Short | −128 … 127 |
int | Integer | −128 … 127 (upper bound tunable) |
long | Long | −128 … 127 |
char | Character | 0 … 127 |
boolean | Boolean | TRUE / FALSE |
float / double | Float / Double | none |
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(5); // autoboxing: Integer.valueOf(5)
int first = list.get(0); // unboxing: list.get(0).intValue()
Integer total = 0;
for (int i = 1; i <= 3; i++) total += i; // unbox, add, box again each time
System.out.println(first + " " + total);
System.out.println(Integer.parseInt("123") + 1); // String → int
System.out.println(Integer.valueOf("123").getClass().getSimpleName());
System.out.println(Integer.toBinaryString(10) + " " + Integer.toHexString(255));
System.out.println(Character.isDigit('7') + " " + Character.toUpperCase('q'));
}
}5 6
124
Integer
1010 ff
true QThe Integer cache trap
Integer.valueOf returns cached objects for −128…127. == on wrappers compares references, so it “works” for small numbers and breaks for bigger ones.
public class Main {
public static void main(String[] args) {
Integer a = 127, b = 127;
Integer c = 128, d = 128;
System.out.println(a == b); // same cached object
System.out.println(c == d); // two different objects
System.out.println(c.equals(d)); // compare values
System.out.println(c.intValue() == d); // one side primitive → unboxes → value compare
}
}true
false
true
trueNullPointerException from unboxing
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String, Integer> stock = new HashMap<>();
stock.put("apple", 3);
try {
int bananas = stock.get("banana"); // get → null → null.intValue()
System.out.println(bananas);
} catch (NullPointerException e) {
System.out.println("NPE while unboxing");
}
int safe = stock.getOrDefault("banana", 0);
System.out.println(safe);
}
}NPE while unboxing
0Performance cost
Each boxed value is a separate heap object (~16 bytes vs 4 for an
int), plus the reference.Summing into a
Longinside a loop creates millions of garbage objects — use a primitivelong.Prefer
int[]overList<Integer>andIntStreamoverStream<Integer>for heavy numeric work.
What does Integer a = 1000, b = 1000; a == b print, and why?
Why do we need wrapper classes?
Can the Integer cache range be changed?