Java Wrapper Classes
Table of Contents + β
In the last lesson you learned about Java constants. Primitives like int and double are fast and simple, but a plain primitive cannot go in a list, be empty, or carry methods. So Java gives every primitive a matching object form, and we call these wrapper classes.
π€ Why do wrapper classes exist?
A primitive is a raw value with nothing around it. Fast and small, but limited. A wrapper is that same value wrapped in an object, which unlocks three things:
- Works with collections. Lists, sets, and maps hold only objects, so
ArrayList<int>does not compile.ArrayList<Integer>does. - Can be
null. AnIntegercan hold a number ornullto mean βno value yetβ. A plainintcan never be empty. - Carries methods. Wrappers bring tools like
Integer.parseInt,Integer.MAX_VALUE, andInteger.compare. A bareinthas none.
πΊοΈ The full primitive to wrapper mapping
Each of Javaβs eight primitives has exactly one wrapper. Most just capitalize the name. Two are odd ones: int becomes Integer (not Int), and char becomes Character (not Char).
| Primitive | Wrapper class |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
π¦ Creating a wrapper: valueOf vs new
There are two ways to create a wrapper. This code makes an Integer both ways and prints them.
Integer a = Integer.valueOf(42); // β
preferred wayInteger b = new Integer(42); // β old, avoid thisSystem.out.println(a);System.out.println(b);Walking through it:
Integer.valueOf(42)hands you an object holding 42, and for small common numbers it reuses the same cached object. This saves memory, so it is the recommended way.new Integer(42)builds a brand new object every time. It wastes memory and Java now marks it outdated, so avoid it.
Output
4242Both print 42. That cached reuse on valueOf leads to one of Javaβs most famous traps, coming up soon.
Skip new Integer
The new Integer(...) style is deprecated, which means Java officially discourages it. Always create wrappers with Integer.valueOf(...), Double.valueOf(...), and so on. In everyday code, autoboxing (next lesson) does this for you automatically.
π οΈ Useful static methods on wrappers
The payoff of wrappers is their toolbox of methods. These are static, so you call them on the class itself, like Integer.parseInt(...), not on an object.
This code shows the biggest and smallest values an int can hold, two constants every wrapper provides.
System.out.println(Integer.MAX_VALUE);System.out.println(Integer.MIN_VALUE);System.out.println(Long.MAX_VALUE);Integer.MAX_VALUE and Integer.MIN_VALUE are built-in constants for the typeβs limits, so you never memorise the exact numbers.
Output
2147483647-21474836489223372036854775807This code converts an int to a String and compares two values.
String text = Integer.toString(99); // number to textSystem.out.println(text);
int result = Integer.compare(5, 8); // -1 if first is smallerSystem.out.println(result);Reading the methods:
Integer.toString(99)gives the text"99".Integer.compare(5, 8)returns negative because 5 is smaller, zero if equal, positive if the first is bigger.
Output
99-1π’ Parsing strings into numbers
A user types "42" and it arrives as text, a String. You cannot do math on text. Parsing reads a string and produces the number it represents.
This code reads two strings, turns them into real numbers, then adds them.
String input1 = "42";String input2 = "100";
int x = Integer.parseInt(input1);int y = Integer.parseInt(input2);
System.out.println(x + y); // real addition, not text joiningInteger.parseInt(input1) reads "42" and gives back the number 42, so x + y does true math and gives 142. If these stayed strings, + would glue them into "42100" instead.
Output
142Each wrapper has its own parse method: Double.parseDouble, Long.parseLong, Boolean.parseBoolean. This example parses a decimal and a true/false value.
double price = Double.parseDouble("3.14");boolean active = Boolean.parseBoolean("true");System.out.println(price);System.out.println(active);Output
3.14trueWatch out: passing non-number text like Integer.parseInt("hello") throws NumberFormatException and stops the program. So parse only text you trust, or handle that error.
πͺ€ The Integer cache and the == trap
This trap confuses almost everyone, so go slowly. The key facts:
- On primitives,
==compares values, so5 == 5istrue. - On objects like
Integer,==checks whether both variables point at the very same object in memory, not whether values match. - To save memory, Java caches
Integerobjects for -128 to 127. In that range you get the same shared object; outside it you get a fresh object each time.
This code compares two small Integer values inside the cache range.
Integer a = Integer.valueOf(100);Integer b = Integer.valueOf(100);System.out.println(a == b); // same cached objectSystem.out.println(a.equals(b)); // compares the values100 is inside the cache, so both point at the same object and == says true. Looks fine, which is exactly why the trap is dangerous.
Output
truetrueNow bump the numbers above 127 and run the same code.
Integer a = Integer.valueOf(200);Integer b = Integer.valueOf(200);System.out.println(a == b); // two different objects!System.out.println(a.equals(b)); // still compares the values200 is outside the cache, so a and b are two separate objects. == sees two objects and says false, even though both hold 200. But .equals(b) looks at the value and correctly says true.
Output
falsetrueSee the trap? The same code gives true for 100 and false for 200, just because of an invisible cache. Such a bug can hide for months and only break on big numbers. The rule that saves you: never use == on wrapper objects, always use .equals(). For primitives, == is still fine.
The one rule to remember
For wrapper objects like Integer, use .equals() to compare values. Use == only on primitives. Mixing them up gives wrong answers that depend on the size of the number.
π A quick preview of autoboxing
You rarely type Integer.valueOf(...) by hand. Java converts between a primitive and its wrapper for you. Turning int into Integer is autoboxing; the reverse, Integer to int, is unboxing.
This code stores a plain int straight into an Integer variable, with no valueOf in sight.
Integer boxed = 7; // autoboxing: int 7 becomes an Integerint back = boxed; // unboxing: Integer becomes int 7System.out.println(boxed);System.out.println(back);Java added Integer.valueOf(7) for you on the first line and pulled the value out on the second. Seamless, but it hides one sharp edge around null, covered next.
Output
77β οΈ Common Mistakes
These wrapper slip-ups bite almost every learner.
Using == to compare wrappers. It checks object identity, not value, and the answer depends on the hidden cache. Use .equals() instead.
// β Avoid: works for small numbers, breaks for big onesInteger a = 200, b = 200;if (a == b) System.out.println("equal");
// β
Good: compares the actual values, alwaysif (a.equals(b)) System.out.println("equal");Unboxing a null wrapper. If an Integer is null and you use it where an int is needed, Java tries to unbox null and throws a NullPointerException.
// β Avoid: count is null, so this crashes when unboxingInteger count = null;int total = count + 1; // NullPointerException
// β
Good: check for null firstInteger count = null;int total = (count == null) ? 0 : count + 1;Creating wrappers with new. It always builds a fresh object and wastes memory, and Java marks it as deprecated.
// β Avoid: old, deprecated, makes a needless objectInteger n = new Integer(42);
// β
Good: lets Java reuse cached objectsInteger n = Integer.valueOf(42);β Best Practices
- Compare wrappers with
.equals(). Save==for primitives only. This avoids the cache trap completely. - Create wrappers with
valueOf. UseInteger.valueOf(...)overnew Integer(...), or just let autoboxing do it. - Prefer primitives by default. Reach for a wrapper only when you need a collection, a
nullvalue, or a wrapper method. Primitives are faster and cannot benull. - Guard against
nullbefore unboxing. Any wrapper that might benullshould be checked before you use it as a primitive. - Use the built-in constants and methods.
Integer.MAX_VALUE,Integer.parseInt, andInteger.comparealready exist. Do not reinvent them. - Parse only trusted text. Wrap
parseIntin a check or error handler if the text might not be a real number.
π§© What Youβve Learned
- β
Every primitive has a matching wrapper class, like
inttoIntegerandchartoCharacter. - β
Wrappers exist so values can go in collections, can be
null, and can carry useful methods. - β
Create them with
Integer.valueOf(...), not the deprecatednew Integer(...). - β
Wrappers give you tools like
parseInt,toString,MAX_VALUE, andcompare. - β
Java caches
Integervalues from -128 to 127, which makes==unreliable on wrappers. Always use.equals(). - β
Unboxing a
nullwrapper throws aNullPointerException, so check for null first.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What is the wrapper class for the primitive int?
Why: The wrapper for int is Integer, not Int. The wrapper for char is Character, also an odd one to remember.
- 2
Why should you use .equals() instead of == to compare two Integer objects?
Why: For objects, == checks if both point at the same object. Because of the -128 to 127 cache, that answer depends on the number. .equals() compares the actual values.
- 3
Which is the preferred way to create an Integer wrapper?
Why: Integer.valueOf(42) is preferred because it can reuse cached objects. new Integer(...) is deprecated and always makes a new object.
- 4
What happens if you unbox a null Integer into an int?
Why: Unboxing tries to pull a primitive value out of the object. A null wrapper has no value, so Java throws a NullPointerException. Check for null first.
π Whatβs Next?
You just saw Java quietly turn an int into an Integer and back again. That magic has a name, and a sharp edge around null that is worth understanding fully. Letβs look at how boxing really works.