== vs equals() en Java: Diferencias y Cuándo Usar Cada Uno
Aprende la diferencia real entre == y equals() en Java con ejemplos de Strings, objetos propios y el caso del caché de Integer.
En Java, == y equals() sirven para comparar, pero no hacen lo mismo: == compara referencias de memoria (o valores, en el caso de primitivos), mientras que equals() compara el contenido lógico de dos objetos según cómo lo defina su clase.
¿Qué hace realmente == en Java?
Con tipos primitivos (int, double, boolean...), == compara directamente los valores. Con objetos, == compara si ambas variables apuntan exactamente a la misma dirección de memoria.
int a = 5;
int b = 5;
System.out.println(a == b); // true, compara valores
¿Qué hace equals()?
equals() es un método heredado de Object que, por defecto, se comporta igual que == (compara referencias). Muchas clases de Java, como String, lo sobreescriben para comparar el contenido en lugar de la referencia.
== vs equals() con tipos primitivos
Con primitivos solo existe ==, ya que no son objetos y no tienen métodos. No se puede llamar a .equals() sobre un int directamente (a menos que esté autoboxeado a Integer).
== vs equals() con Strings (el caso que confunde a todos)
String s1 = "hola";
String s2 = "hola";
String s3 = new String("hola");
System.out.println(s1 == s2); // true (mismo literal, mismo pool de Strings)
System.out.println(s1 == s3); // false (objetos distintos en memoria)
System.out.println(s1.equals(s3)); // true (mismo contenido)
Los literales de String se almacenan en un String Pool, por lo que dos literales idénticos pueden compartir referencia. Pero un String creado con new siempre genera un objeto nuevo en memoria. La recomendación es siempre usar equals() para comparar contenido de Strings, nunca ==.
== vs equals() con objetos propios
class Punto {
int x, y;
Punto(int x, int y) { this.x = x; this.y = y; }
}
Punto p1 = new Punto(1, 2);
Punto p2 = new Punto(1, 2);
System.out.println(p1 == p2); // false, referencias distintas
System.out.println(p1.equals(p2)); // false, porque no hemos sobreescrito equals()
Sin sobreescribir equals(), la clase hereda el comportamiento por defecto de Object, que compara referencias, igual que ==.
Sobreescribir equals() y hashCode() correctamente
class Punto {
int x, y;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Punto)) return false;
Punto p = (Punto) o;
return x == p.x && y == p.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
La regla es estricta: si sobreescribes equals(), siempre debes sobreescribir también hashCode(). Estructuras como HashMap o HashSet usan hashCode() para ubicar el objeto y luego equals() para confirmar la igualdad; si solo sobreescribes uno de los dos, esas colecciones pueden comportarse de forma inconsistente.
Desde Java 16, los record generan automáticamente equals() y hashCode() coherentes basados en sus componentes, evitando este problema por completo.
Tabla resumen: cuándo usar == y cuándo equals()
| Tipo de dato | Usa == | Usa equals() |
|---|---|---|
| Primitivos (int, double...) | Sí | No aplica |
| String | No | Sí |
| Objetos propios | Solo para comprobar identidad exacta | Sí, para comparar contenido |
| Enums | Sí (es seguro, referencia única por constante) | También válido |
Errores comunes (incluyendo el caché de Integer -128 a 127)
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true, por el caché interno de Integer
Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false, fuera del rango cacheado
Java cachea internamente los objetos Integer entre -128 y 127 por eficiencia. Esto provoca que == funcione "por casualidad" en ese rango y falle fuera de él, un error clásico y muy citado en entrevistas técnicas. La solución, de nuevo, es usar siempre equals() para comparar wrappers.
Preguntas frecuentes
¿Por qué == funciona a veces con Strings? Porque los literales de String comparten el String Pool. Pero es un comportamiento poco fiable: nunca debe usarse como método de comparación intencional.
¿Qué pasa si sobreescribo equals() pero no hashCode()?
La clase puede comportarse de forma incorrecta dentro de estructuras como HashMap o HashSet, ya que ambos métodos deben ser coherentes entre sí.
¿Los enums se comparan con == o equals()?
Con == es seguro, ya que cada constante de un enum es única en la JVM. Ambas opciones son válidas.
Siguiente paso
Comprender bien esta diferencia es clave antes de trabajar con estructuras de datos como HashMap, o antes de definir correctamente un Java Bean con sus propios métodos equals() y hashCode().
Newsletter Semanal de Java
Cada viernes recibe lo más nuevo del ecosistema Java: frameworks, herramientas y mejores prácticas.
🔒 Sin spam. Cancela cuando quieras.