16. .equals() on out-of-cache Integers
Integer a = 200;
Integer b = 200;
System.out.println(a.equals(b));
Output: true
== fails for two out-of-cache boxed Integers (question 15), but .equals() compares the wrapped values, which are both 200 — so it is true. Always use .equals() for wrapper comparison.
17. Integer == int unboxing ⭐⭐⭐⭐⭐
Integer a = 100;
int b = 100;
System.out.println(a == b);
Output: true
When one operand is a primitive int, the Integer is unboxed and == compares values: 100 == 100 → true. The unboxing rule overrides the reference-comparison behavior you’d get between two Integer objects.
18. Double wrapper comparison
Double a = 10.5;
Double b = 10.5;
System.out.println(a == b);
System.out.println(a.equals(b));
Output:
false
true
Double has no guaranteed cache like Integer’s -128..127 range, so the two autoboxed objects are distinct — == is false. .equals() compares the double values → true.
19. == on two separately created objects ⭐⭐⭐⭐⭐
class Student {
int age;
Student(int age) {
this.age = age;
}
}
public class Test {
public static void main(String[] args) {
Student s1 = new Student(20);
Student s2 = new Student(20);
System.out.println(s1 == s2);
}
}
Output: false
Each new allocates a separate object. == compares references, and the two references point to different objects — even though the age fields are equal. Without an overridden equals(), object identity is all == sees.
20. == on the same object reference
Student s1 = new Student(20);
Student s2 = s1;
System.out.println(s1 == s2);
Output: true
Student s2 = s1 copies the reference, not the object. Both variables point to the same object, so == is true. This is the counterpart to question 19.
21. == against null
String s = null;
System.out.println(s == null);
Output: true
s contains the null reference. s == null is true — comparing any reference variable to null tests whether it is null.
22. == between two null references
String a = null;
String b = null;
System.out.println(a == b);
Output: true
Both variables hold the same null reference, so a == b is true. There is only one null — every null reference is identical.
23. Calling .equals() on a null reference
String a = null;
System.out.println(a.equals("Java"));
Output: NullPointerException
You cannot call an instance method on null. a.equals(...) dereferences a, which is null, and throws NullPointerException before any comparison happens.
24. Safe null comparison with .equals() ⭐⭐⭐⭐⭐
String a = null;
System.out.println("Java".equals(a));
Output: false
Calling equals() on the literal is safe — the receiver is a valid object. It compares "Java" against null and returns false (no exception). This is the recommended pattern for null-safe comparison.
25. Compile-time constant concatenation and ==
String a = "Java";
String b = "Ja" + "va";
System.out.println(a == b);
Output: true
"Ja" + "va" is a compile-time constant, folded to "Java" by the compiler. It resolves to the same string-pool object as a, so == is true. Constant folding keeps both references in the pool.
26. Runtime String concatenation ⭐⭐⭐⭐⭐
String a = "Java";
String b = "Ja";
String c = b + "va";
System.out.println(a == c);
System.out.println(a.equals(c));
Output:
false
true
b + "va" is a runtime concatenation, which creates a new String object — it is not pooled. So a == c is false. The content is still "Java", so .equals() is true. Whether concatenation is compile-time or runtime decides pool membership.
27. StringBuilder comparison ⭐⭐⭐⭐⭐
StringBuilder a = new StringBuilder("Java");
StringBuilder b = new StringBuilder("Java");
System.out.println(a == b);
System.out.println(a.equals(b));
Output:
false
false
a and b are distinct objects → == is false. Crucially, StringBuilder does not override equals() for content, so a.equals(b) falls back to Object.equals() — reference identity — and is also false. To compare contents you must call .toString().equals(...).
28. == on two separate subclass instances
class Animal {}
class Dog extends Animal {}
public class Test {
public static void main(String[] args) {
Animal a = new Dog();
Animal b = new Dog();
System.out.println(a == b);
}
}
Output: false
Both references have type Animal, but each new Dog() creates a separate object. Inheritance does not change reference comparison — == still checks identity, so the result is false.
29. Boolean comparison
boolean a = true;
boolean b = false;
System.out.println(a == b);
System.out.println(a != b);
Output:
false
true
boolean is a primitive; == compares values. true == false is false, and true != false is true.
30. The classic mixed comparison ⭐⭐⭐⭐⭐
public class Test {
public static void main(String[] args) {
String s1 = "Java";
String s2 = "Java";
String s3 = new String("Java");
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1.equals(s3));
System.out.println(i1 == i2);
System.out.println(i3 == i4);
System.out.println(i3.equals(i4));
}
}
Output:
true
false
true
true
false
true
Everything above in one place: s1 == s2 pooled literals → true; s1 == s3 distinct new object → false; .equals() content → true. For the wrappers, i1/i2 share the cached 100 object → true; i3/i4 at 200 are outside the cache → false for ==, true for .equals(). Memorize this output set and you have the whole comparison chapter covered.
Premium Content
Unlock Comparison Questions - Part 2 and all premium lessons with a subscription.
From ₹199.99/year — See plans