Java Wrapper Classes

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. An Integer can hold a number or null to mean β€œno value yet”. A plain int can never be empty.
  • Carries methods. Wrappers bring tools like Integer.parseInt, Integer.MAX_VALUE, and Integer.compare. A bare int has 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 way
Integer b = new Integer(42); // ❌ old, avoid this
System.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

42
42

Both 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
-2147483648
9223372036854775807

This code converts an int to a String and compares two values.

String text = Integer.toString(99); // number to text
System.out.println(text);
int result = Integer.compare(5, 8); // -1 if first is smaller
System.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 joining

Integer.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

142

Each 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.14
true

Watch 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, so 5 == 5 is true.
  • 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 Integer objects 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 object
System.out.println(a.equals(b)); // compares the values

100 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

true
true

Now 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 values

200 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

false
true

See 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 Integer
int back = boxed; // unboxing: Integer becomes int 7
System.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

7
7

⚠️ 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 ones
Integer a = 200, b = 200;
if (a == b) System.out.println("equal");
// βœ… Good: compares the actual values, always
if (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 unboxing
Integer count = null;
int total = count + 1; // NullPointerException
// βœ… Good: check for null first
Integer 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 object
Integer n = new Integer(42);
// βœ… Good: lets Java reuse cached objects
Integer n = Integer.valueOf(42);

βœ… Best Practices

  • Compare wrappers with .equals(). Save == for primitives only. This avoids the cache trap completely.
  • Create wrappers with valueOf. Use Integer.valueOf(...) over new Integer(...), or just let autoboxing do it.
  • Prefer primitives by default. Reach for a wrapper only when you need a collection, a null value, or a wrapper method. Primitives are faster and cannot be null.
  • Guard against null before unboxing. Any wrapper that might be null should be checked before you use it as a primitive.
  • Use the built-in constants and methods. Integer.MAX_VALUE, Integer.parseInt, and Integer.compare already exist. Do not reinvent them.
  • Parse only trusted text. Wrap parseInt in 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 int to Integer and char to Character.
  • βœ… Wrappers exist so values can go in collections, can be null, and can carry useful methods.
  • βœ… Create them with Integer.valueOf(...), not the deprecated new Integer(...).
  • βœ… Wrappers give you tools like parseInt, toString, MAX_VALUE, and compare.
  • βœ… Java caches Integer values from -128 to 127, which makes == unreliable on wrappers. Always use .equals().
  • βœ… Unboxing a null wrapper throws a NullPointerException, so check for null first.

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 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. 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. 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. 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.

Java Autoboxing and Unboxing

Share & Connect