SwadhyAI Notes

All Java notes

Java Wrapper Classes

›Short versionOpen if you only have a minute.
  • A wrapper is an immutable object holding one primitive: int pairs with Integer, boolean with Boolean, char with Character.
  • Autoboxing compiles to valueOf. Unboxing compiles to intValue, booleanValue, and the other *Value methods.
  • Collections and generic types store objects. ArrayList<int> is illegal. ArrayList<Integer> is the list of ints.
  • Integer identity is shared for -128 through 127. Outside that range == is not a value comparison. Use equals, or unbox to a primitive.
  • Unboxing null throws NullPointerException. A primitive variable cannot represent "missing."
  • parseInt returns an int. valueOf returns a wrapper. Long.equals does not accept an Integer just because both hold 10.

An int is the number. An is an object whose only job is to carry that number into a place that refuses primitives. ArrayList is such a place. So is any generic type, and so is a field that must be allowed to be absent.

The conversion is cheap to write and easy to misread. hides a method call. hides another. The failures show up when you compare two objects with ==, or when the object you unbox was null.

Eight primitives, eight types

PrimitiveWrapperWhat it holds
byteByte8-bit signed integer
shortShort16-bit signed integer
intInteger32-bit signed integer
longLong64-bit signed integer
floatFloat32-bit IEEE 754
doubleDouble64-bit IEEE 754
booleanBooleantrue or false
charCharacterUTF-16 code unit

Keep the primitive when you are counting, looping, or doing arithmetic. Reach for the wrapper when the signature demands an object, when a generic type parameter has to be filled, or when null is a meaningful answer. A hot loop that boxes on every iteration allocates once the number leaves the cache. The primitive never did.

What the compiler inserts

java
Integer boxed = Integer.valueOf(5); // what "Integer boxed = 5" compiles toward
int plain = boxed.intValue();

ArrayList<Integer> scores = new ArrayList<>();
scores.add(10); // valueOf(10), then stored as an object

int parsed = Integer.parseInt("123");
Integer fromText = Integer.valueOf("123");
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648

stays on the primitive. That is the right call when the next step is arithmetic. valueOf is the right call when the next step needs an object. Both reject a malformed string with NumberFormatException.

ArrayList<int> does not compile. The list stores references. The element type has to be a reference type, so the scores live as Integer. Reading one back into an int unboxes it.

Identity, value, and a null that unboxes

Integer.valueOf returns one shared object for each value from -128 to 127, so two boxings of 127 are the same object. Two boxings of 128 are under no such requirement, though a JVM is allowed to cache further. Code that used == and passed its tests on small fixtures starts failing when a real id crosses 127. That is the whole trap of the .

java
Integer smallA = 127;
Integer smallB = 127;
System.out.println(smallA == smallB); // true: the required cache

Integer bigA = 128;
Integer bigB = 128;
System.out.println(bigA == bigB);     // not a promise

System.out.println(smallA.equals(smallB)); // true
System.out.println(bigA.equals(bigB));     // true

Integer missing = null;
// int value = missing; // NullPointerException in intValue()

Long total = 10L;
System.out.println(total.equals(10));  // false: 10 boxes to Integer
System.out.println(total.equals(10L)); // true
System.out.println(total == 10L);      // true: unbox, then compare longs

is the comparison that means "same wrapped value of the same wrapper type." Comparing two wrappers with == means "same object," which the cache makes true for a band of small integers and leaves unspecified afterward. Comparing a wrapper to a primitive unboxes first, and that path throws if the wrapper is null.

Integer a = 200; Integer b = 200; a == b is false in your run, and a.equals(b) is true. Which result is the value comparison, and why did == disagree?

equals is the value comparison. Both objects wrap 200. == asked whether they are the same object. 200 sits outside the range where boxing must reuse one instance, so these two valueOf calls were free to return different objects. The same program with 100 can print true for ==, because 100 is inside the required cache. That flip is why wrapper identity is the wrong tool for numeric equality.