Java › equals(), hashCode() & toString() Contracts
What is the relationship between equals() and the == operator when comparing primitive types versus reference types, and how does this affect comparing boxed wrapper types like Integer?
IntermediateAnswer
== between primitives compares actual values directly (numeric or boolean equality); == between reference types (including boxed wrapper types like Integer) compares object identity (whether both references point to the same object instance) rather than logical value equality -- this creates a notorious pitfall with boxed types due to Integer's internal caching of small values (-128 to 127 by default): == happens to "work" correctly for cached small values purely by coincidence (both variables reference the same cached instance) but silently breaks for larger values outside that cache range, making == fundamentally unreliable for comparing boxed wrapper type values and .equals() (or unboxing to a primitive first) the only genuinely correct approach.
Integer a = 100, b = 100;
System.out.println(a == b); // true, coincidentally -- both within the cached range (-128 to 127)
Integer c = 200, d = 200;
System.out.println(c == d); // false! Outside the cache range, two genuinely distinct Integer objects
System.out.println(c.equals(d)); // true, correctly compares actual values regardless of cachingReal-world example A subtle production bug where a numeric comparison worked correctly in testing (using small sample values under 128) but failed unpredictably in production (with larger real-world values) is traced to using == instead of .equals() to compare two Integer objects, exploiting a misunderstanding of Integer's internal small-value caching behavior.