Wrapper Classes in Java – Autoboxing, Unboxing and Conversions
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
| Primitive | Wrapper class | Cached values (valueOf) |
|---|---|---|
byte | Byte | All (−128 to 127) |
short | Short | −128 to 127 |
int | Integer | −128 to 127 (upper bound configurable) |
long | Long | −128 to 127 |
float | Float | None |
double | Double | None |
char | Character | 0 to 127 |
boolean | Boolean | TRUE 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):
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);
}
}
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
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());
}
}
}
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"
| Method | Returns | Example |
|---|---|---|
parseXxx(String) | Primitive | Integer.parseInt("42") |
valueOf(String / primitive) | Wrapper (uses the cache) | Integer.valueOf(42) |
xxxValue() | Primitive | num.doubleValue() |
toString(primitive) | String | Integer.toString(42) |
compare, max, min, sum | int / primitive | Integer.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
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!
}
}
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:
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);
}
}
missing = null NullPointerException when unboxing null safe = 0
6. Primitive or Wrapper?
| Use a primitive when… | Use a wrapper when… |
|---|---|
| Doing calculations, loops and counters | Storing values in collections or generics |
| Performance and memory matter | A value may be absent (null), such as an optional database column |
| Default value 0/false is meaningful | You 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
parseXxxfor primitives andvalueOffor wrappers; watch forNumberFormatException. - Compare wrappers with
equals(), not==, because of caching. - Unboxing
nullthrowsNullPointerException.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is a wrapper class in Java?
A class that wraps a primitive value in an object, such as Integer for int.
Q2. Why do we need wrapper classes?
Collections and generics work only with objects, wrappers can represent null, and they provide constants and conversion methods.
Q3. What is autoboxing?
The automatic conversion of a primitive to its wrapper by the compiler, for example Integer x = 5;.
Q4. What is unboxing?
The automatic conversion of a wrapper to its primitive, for example int y = x;.
Q5. Are wrapper classes immutable?
Yes. Their values cannot change; arithmetic produces new objects.
Q6. Why does Integer == Integer sometimes return false?
== compares references. Values from −128 to 127 come from a cache and share objects; larger values usually do not.
Q7. What is the difference between parseInt and valueOf?
parseInt returns a primitive int; valueOf returns an Integer object, possibly cached.
Q8. What happens when parsing an invalid number?
NumberFormatException is thrown.
Q9. What happens when unboxing null?
A NullPointerException is thrown.
Q10. Which wrapper classes extend Number?
Byte, Short, Integer, Long, Float and Double. Character and Boolean do not.
Q11. Are wrapper constructors deprecated?
Yes. Constructors like new Integer(5) are deprecated for removal since Java 9/16; use valueOf or autoboxing.
Q12. Can I change the Integer cache size?
The upper bound can be raised with -XX:AutoBoxCacheMax=<n>. The lower bound stays −128.
Q13. Is autoboxing slow?
It can be in tight loops, because it may allocate objects. Use primitives or primitive streams for heavy numeric work.
Q14. Why does Long.equals(Integer) return false?
equals requires the same wrapper type, so a Long and an Integer are never equal even with the same value.
Q15. What is the default value of a wrapper field?
null, unlike primitive fields, which default to 0 or false.
Q16. How do I convert a String to an int?
Integer.parseInt(text), after trimming if needed, handling NumberFormatException.
Q17. How do I convert an int to binary or hex?
Integer.toBinaryString(n) and Integer.toHexString(n); parse back with Integer.parseInt(text, radix).
Q18. Can wrappers be used in switch statements?
Yes. Integer, Character, Short and Byte are unboxed automatically, but a null value throws NullPointerException.
Q19. What does Boolean.parseBoolean return for "yes"?
false. Only "true" (ignoring case) gives true; it never throws.
Q20. When was autoboxing introduced?
In Java 5, together with generics.