equals() vs == en Java, el primer tropiezo casi garantizado

Angel Carrero
12 de Agosto del 2026

Con varios hilos por aquí de comparaciones que «deberían funcionar y no funcionan», un recordatorio sobre equals() vs == en Java, porque es de los primeros tropiezos casi garantizados.

== compara si dos variables apuntan al mismo objeto en memoria, no si tienen el mismo contenido. Para tipos primitivos (int, double...) esto no importa, ahí == sí compara valores. Pero para objetos, incluido String, es otra historia:

String a = new String("hola");
String b = new String("hola");

System.out.println(a == b);     // false, son dos objetos distintos en memoria
System.out.println(a.equals(b)); // true, el CONTENIDO es igual

Lo que confunde aún más: si en vez de new String(...) escribes String a = "hola"; String b = "hola";, entonces a == b da true, porque Java reutiliza literales de texto idénticos del «string pool». Eso hace que el bug parezca funcionar «a veces sí, a veces no» según cómo se hayan creado las cadenas, lo cual es todavía más confuso que si fallara siempre.

Regla simple: para objetos (String, tus propias clases, wrappers como Integer en ciertos rangos...), usa siempre .equals() para comparar contenido. == solo para tipos primitivos, o cuando de verdad quieras saber si es literalmente el mismo objeto (poco habitual).

Si tienes tus propias clases y quieres que .equals() compare por contenido en vez de por identidad (comportamiento por defecto heredado de Object, que en el fondo hace lo mismo que ==), tienes que sobreescribirlo tú mismo:

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (!(obj instanceof Persona)) return false;
    Persona otra = (Persona) obj;
    return this.dni.equals(otra.dni);
}

Angel Carrero


David Carrero
12 de Agosto del 2026

Para rematar el tropiezo con un ejemplo concreto que confunde aún más al principio: con Integer, comparar con == a veces "funciona" por pura casualidad, y eso es peor que si fallara siempre.

Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true (!)

Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false

Esto pasa porque Java cachea internamente los objetos Integer del -128 al 127 (el IntegerCache), así que al autoboxear un valor dentro de ese rango, a y b acaban apuntando al mismo objeto en memoria, y == (que compara referencias, no valores) da true por casualidad. Fuera de ese rango, cada autoboxing crea un objeto nuevo, y == vuelve a dar false aunque el valor numérico sea idéntico.

Es un ejemplo perfecto de por qué la regla "usa siempre .equals() para comparar objetos, nunca ==" no admite excepciones aunque alguna vez parezca que == funciona: el hecho de que funcione a veces con números pequeños es justo lo que hace que el bug se cuele en producción y solo aparezca cuando los valores reales superan 127.

David