HuntExams Academy logo
JavaIntermediate#puzzle#fundamentals

What does this print? Integer a = 127; Integer b = 127; Integer c = 128; Integer d = 128; System.out.println(a == b); System.out.println(c == d);

Answer

It prints true, then false. Why: both lines compare object references with ==, not values. Autoboxing an int into an Integer goes through Integer.valueOf(int), which returns objects from an internal cache for the range -128 to 127. So a and b are literally the same cached object and a == b is true. 128 is outside the cache, so valueOf allocates a new Integer each time; c and d are two distinct objects and c == d is false \u2014 even though c.equals(d) is true. Key facts to state in the interview: - The cache lives in java.lang.Integer.IntegerCache, and the JLS requires it for -128..127. - The upper bound is tunable with -XX:AutoBoxCacheMax=<n> (the lower bound is fixed), which makes relying on == doubly fragile. - Other wrappers cache too: Byte, Short, Long and Character (0..127) cache the same low range, and Boolean caches both values. Float and Double never cache, so Double d1 = 1.0, d2 = 1.0 gives d1 == d2 as false. - new Integer(127) == new Integer(127) is always false, because new always allocates. That constructor has been deprecated since Java 9. - Mixing types changes everything: if either operand is a primitive int, the wrapper is UNBOXED and == compares numeric values. So Integer c = 128; int e = 128; c == e is true. - The rule: compare wrapper objects with equals(), Objects.equals() or compareTo(), or unbox explicitly with intValue(). Reserve == for primitives. - Watch the NullPointerException risk when unboxing a null Integer inside a comparison.

Example

Integer a = 127, b = 127;
Integer c = 128, d = 128;
System.out.println(a == b);        // true  -> same cached object
System.out.println(c == d);        // false -> two separate objects
System.out.println(c.equals(d));   // true  -> correct value comparison

// What the compiler actually does
Integer x = Integer.valueOf(127);  // from IntegerCache
Integer y = Integer.valueOf(128);  // a new Integer

// new always allocates
System.out.println(new Integer(127) == new Integer(127));  // false

// One primitive operand forces unboxing -> value comparison
int prim = 128;
System.out.println(c == prim);     // true

// Doubles are never cached
Double p = 1.0, q = 1.0;
System.out.println(p == q);        // false

// Safe patterns
System.out.println(c.intValue() == d.intValue());  // true
System.out.println(Objects.equals(c, d));          // true, null-safe

Detailed explanation

With the usual Integer cache configuration, this code prints true followed by false, each on a separate line. The important qualification is that false for the second line is not guaranteed across all JVM configurations: an implementation may cache 128 as well. Both comparisons use == between two Integer references, so Java checks whether the operands refer to the same object, not whether those objects contain equal numeric values.

The assignments use autoboxing, which converts primitive int values into Integer objects. The Java compiler normally implements these assignments through Integer.valueOf(int). That method always caches values from -128 through 127 inclusive and may cache additional values. Consequently, a and b refer to the same cached object. With the usual cache upper bound of 127, separate calls for 128 create distinct objects, so c and d refer to different objects. In OpenJDK, this cache is maintained by the internal Integer.IntegerCache class. HotSpot allows its upper bound to be increased with -XX:AutoBoxCacheMax=<n>; if the configured cache includes 128, both lines print true.

For numeric equality between Integer objects, c.equals(d) returns true regardless of whether the objects share an identity. Objects.equals(c, d) also returns true here and handles null references safely. Explicitly comparing c.intValue() and d.intValue() works for non-null operands, but throws NullPointerException if either reference is null. If one operand is a primitive int, such as c == 128, Java unboxes the Integer and performs a numeric comparison instead. That comparison is true here, but the same null risk applies.

Interviewers use this question to test whether you distinguish primitives, wrapper objects, autoboxing, and reference identity. A strong answer gives the expected default output first, then explains caching and its configuration-dependent boundary. The language guarantees shared boxing identity for the relevant constant values in the required small range; it does not require different identities outside that range. Therefore, do not build application logic around wrapper identity: use value equality for numbers and == only when primitive equality or intentional reference identity is required.

Key points to remember

  • The usual output is true, then false; an extended Integer cache can make both lines print true.
  • With two Integer operands, == compares reference identity without unboxing.
  • Integer.valueOf caches -128 through 127 inclusive and may cache additional values.
  • Use equals() for Integer value equality or Objects.equals() when nulls are possible.
  • Comparing an Integer with an int triggers unboxing, which can throw NullPointerException.

Common mistakes candidates make

  • Claiming that the second line must always print false because 128 can never be cached.
  • Assuming == compares numeric values whenever both objects are numeric wrappers.
  • Recommending explicit unboxing or instance equals() without considering null operands.

Likely follow-up questions

What happens if the Integer cache includes 128?

Both comparisons print true because each pair refers to a shared cached object. On HotSpot, -XX:AutoBoxCacheMax=128 can extend the cache to include that value.

What does new Integer(127) == new Integer(127) produce?

It produces false because each new expression creates a distinct object rather than using the cache. This constructor has been deprecated since Java 9; prefer autoboxing or Integer.valueOf.

Does Objects.equals consider Integer.valueOf(128) and Long.valueOf(128) equal?

No: Integer.equals requires the other object to be an Integer, so Objects.equals returns false for these different wrapper types. For cross-type numeric comparison, deliberately convert to a suitable common numeric representation.

Interview tip: State the usual output, explain reference identity and autoboxing, then add the extended-cache caveat and a null-safe comparison alternative.

Related Interview Questions

1
JavaBeginner#puzzle#operators

What is the output? public class Test { public static void main(String[] args) { System.out.println(10 / 3); System.out.println(10.0 / 3); System.out.println(10 % 3); } }

Open
2
JavaAdvanced#puzzle#oop

What happens when you compile and run this code? class Parent { static void greet() { System.out.println("Parent"); } } class Child extends Parent { static void greet() { System.out.println("Child"); } } Parent p = new Child(); p.greet();

Open
3
JavaIntermediate#puzzle#arrays

What is the output of this array comparison? int[] a = {1, 2, 3}; int[] b = {1, 2, 3}; System.out.println(a == b); System.out.println(a.equals(b)); System.out.println(Arrays.equals(a, b));

Open