Of course! This is a fundamental concept in Java that often trips up beginners. Let's break it down.

In short: For primitive int types, compares their actual numeric values.
However, the confusion arises because Java also has a wrapper class Integer, and this is where the behavior of gets interesting.
Let's look at the two main scenarios.
Scenario 1: Primitive int vs. Primitive int (The Simple Case)
When you use the operator with two variables of the primitive int type, it directly compares their values stored in memory.

- If the values are equal, returns
true. - If the values are different, returns
false.
This is straightforward and behaves as you'd expect from mathematics.
Code Example:
public class IntComparison {
public static void main(String[] args) {
int a = 10;
int b = 10;
int c = 20;
// Comparing two variables with the same value
System.out.println("a == b: " + (a == b)); // Output: a == b: true
// Comparing two variables with different values
System.out.println("a == c: " + (a == c)); // Output: a == c: false
// Comparing a variable with a literal
System.out.println("a == 10: " + (a == 10)); // Output: a == 10: true
}
}
Why this works: Primitive types like int, double, char, etc., hold their actual value directly. The operator just checks if these values are the same.
Scenario 2: The Trap - Integer vs. Integer (The Wrapper Class)
Java provides a wrapper class, Integer, for the primitive int. This allows you to store int values in collections (like ArrayList) or use them where objects are required (like generics).
The operator with objects behaves differently: it checks if the two variables refer to the exact same object in memory (i.e., they have the same memory address), not if their contents are equal.
For comparing the values of two Integer objects, you should use the .equals() method.
Code Example:
public class IntegerComparison {
public static void main(String[] args) {
Integer x = new Integer(10);
Integer y = new Integer(10);
Integer z = x; // z now points to the SAME object as x
// Comparing two different Integer objects with the same value
// == checks for object identity (same memory location)
System.out.println("x == y: " + (x == y)); // Output: x == y: false
// Comparing an object with itself
// z and x point to the same object in memory
System.out.println("x == z: " + (x == z)); // Output: x == z: true
// The CORRECT way to compare Integer objects for value equality
System.out.println("x.equals(y): " + (x.equals(y))); // Output: x.equals(y): true
}
}
Why this happens:
new Integer(10)creates a brand newIntegerobject in memory.xholds the memory address of the first object.yholds the memory address of the second, different object.- Since
xandypoint to different memory locations,x == yisfalse.
The Special Case: Integer Caching (Autoboxing and -128 to 127)
To improve performance and reduce memory usage, Java has a special feature called integer caching.
When you use an int literal to create an Integer (a process called autoboxing), Java will reuse existing objects from a cache for values between -128 and 127, inclusive.
This means for values in this range, will sometimes appear to work correctly, but it's relying on object identity, not value comparison. This is a common source of bugs because the behavior is inconsistent for numbers outside this range.
Code Example:
public class IntegerCache {
public static void main(String[] args) {
// --- Values within the cached range (-128 to 127) ---
Integer a = 100; // Autoboxing. Java reuses the cached Integer object for 100.
Integer b = 100; // Autoboxing. Java reuses the SAME cached Integer object for 100.
System.out.println("a == b (100): " + (a == b)); // Output: a == b (100): true
// This happens because a and b point to the SAME cached object.
// --- Values outside the cached range ---
Integer c = 200; // Autoboxing. This value is NOT cached, so a new object is created.
Integer d = 200; // Autoboxing. This value is NOT cached, so ANOTHER new object is created.
System.out.println("c == d (200): " + (c == d)); // Output: c == d (200): false
// This happens because c and d point to two different objects in memory.
// --- The SAFE way to compare, always ---
System.out.println("c.equals(d): " + (c.equals(d))); // Output: c.equals(d): true
}
}
Summary Table
| Comparison Type | Example | What Does | When to Use |
|---|---|---|---|
Primitive int |
int a = 5; int b = 5; a == b; |
Compares values. | Always, when working with primitive ints. |
Integer Object (Value) |
Integer a = 5; Integer b = 5; a.equals(b); |
Compares contents (values). | Always when you need to compare the value of two Integer objects. |
Integer Object (Identity) |
Integer a = new Integer(5); Integer b = new Integer(5); a == b; |
Compares memory addresses (are they the same object?). | Very rarely. Useful for checking if two references point to the exact same instance (e.g., in singleton patterns). |
Best Practice
- For primitives (
int,double, etc.), use . - For objects (
Integer,String,MyClass, etc.), use.equals()to compare their values. - Be aware of the
Integercache (-128to127) and never rely on to compareIntegervalues, even if it seems to work in some cases. Always use.equals().
