Java is not purely object-oriented because primitive types (int, double, char…) are not objects.
To allow primitives to be used where objects are required (e.g., Collections, Generics), Java provides Wrapper Classes — object representations of primitive data types.
Each primitive has a corresponding wrapper class:
| Primitive | Wrapper Class |
|---|---|
byte |
Byte |
short |
Short |
int |
Integer |
long |
Long |
float |
Float |
double |
Double |
char |
Character |
boolean |
Boolean |
Wrapper classes are immutable and stored in Heap memory.
- Collections require objects
List<int> list; // ❌ invalid
List<Integer> list; // ✔ valid- Generics require objects
- Object methods (toString(), equals(), hashCode())
- Serialization
- Utility methods (parseInt, valueOf, etc.)
- Autoboxing / Unboxing support
Automatic conversion of primitive into wrapper class.
int x = 10;
Integer y = x; // autoboxingEquivalent to:
Integer y = Integer.valueOf(x);Used frequently in Collections:
List<Integer> list = new ArrayList<>();
list.add(5); // primitive int is autoboxed to IntegerAutomatic conversion of wrapper class into primitive.
Integer a = 20;
int b = a; // unboxingEquivalent to:
int b = a.intValue();Each wrapper class provides useful utility methods.
int x = Integer.parseInt("100");
double d = Double.parseDouble("12.5");
boolean b = Boolean.parseBoolean("true");String s1 = String.valueOf(10);
String s2 = Integer.toString(20);int max = Integer.MAX_VALUE;
int min = Integer.MIN_VALUE;Just like Strings, wrapper classes are immutable. Once created, the value cannot change.
Integer n = 10;
n = 20; // creates new object, does not modify existing oneJava caches Integer objects from –128 to +127.
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true (cached)Outside cache range:
Integer a = 200;
Integer b = 200;
System.out.println(a == b); // false (different objects)Caching applies to:
ByteShortIntegerLongCharacter(0–127)
Not applicable to:
FloatDouble
Autoboxing can cause:
- Unnecessary object creation
- Extra garbage for GC
- Slower performance
Integer sum = 0;
for (int i = 0; i < 100000; i++) {
sum += i; // repeated unboxing + boxing
}Better:
int sum = 0;Integer a = 128;
Integer b = 128;
System.out.println(a == b); // falseSystem.out.println(a.equals(b)); // trueBecause of caching, small integers behave differently:
Integer a = 10;
Integer b = 10;
System.out.println(a == b); // trueCollections cannot store primitives:
ArrayList<int> list; // ❌Correct:
ArrayList<Integer> list = new ArrayList<>();Autoboxing makes usage seamless.
Wrapper classes are part of java.lang package:
Object
├── Number
│ ├── Integer
│ ├── Double
│ ├── Float
│ ├── Long
│ ├── Short
│ └── Byte
├── Boolean
└── Character
Integer i = new Integer(10); // ❌ discouragedInteger i = Integer.valueOf(10);Benefits:
- Uses cached values
- Efficient memory usage
List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);int age = Integer.parseInt("25");Integer value = null;
// int x = value; // throws NullPointerExceptionBecause generics and collections require objects, not primitives.
Automatic conversion between primitive ↔ wrapper types.
To support caching and allow safe sharing.
To reduce memory footprint and improve performance.
Floating numbers have infinite possible values → caching impractical.
valueOf() uses cache; constructors always create new objects.
-
Wrapper classes wrap primitive data types into objects.
-
Used for generics, collections, OOP features.
-
Support autoboxing and unboxing.
-
Immutable objects stored in heap.
-
Integer caching improves performance.
-
Use
equals()to compare values, not==.