JavaRush /Blog Java /Random-ES /Iguales en Java y comparación de cadenas - Comparación de...

Iguales en Java y comparación de cadenas - Comparación de cadenas

Publicado en el grupo Random-ES
¡Hola! Hoy hablaremos de un tema muy importante e interesante, a saber, comparar objetos entre sí iguales () en Java. Y de hecho, ¿en qué casos en Java el Objeto A será igual al Objeto B ? Comparación de iguales y cadenas - 1Intentemos escribir un ejemplo:

public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {
      
       Car car1 = new Car();
       car1.model = "Ferrari";
       car1.maxSpeed = 300;

       Car car2 = new Car();
       car2.model = "Ferrari";
       car2.maxSpeed = 300;

       System.out.println(car1 == car2);
   }
}
Salida de consola:

false
Está bien, detente. ¿Por qué, de hecho, estos dos coches no son iguales? Les dimos las mismas propiedades, pero el resultado de la comparación es falso. La respuesta es simple. El operador ==no compara las propiedades de los objetos, sino los enlaces. Incluso si dos objetos tienen 500 propiedades idénticas, el resultado de la comparación seguirá siendo falso. Después de todo, los enlaces car1apuntan car2 a dos objetos diferentes , a dos direcciones diferentes. Imagine una situación en la que se comparan personas. Probablemente exista una persona en el mundo que tenga el mismo nombre, color de ojos, edad, altura, color de cabello, etc. que tú. Es decir, sois similares en muchos aspectos, pero aún así no sois gemelos y, sobre todo, no sois la misma persona. Comparación de iguales y cadenas - 2El operador aplica aproximadamente la misma lógica ==cuando lo usamos para comparar dos objetos. Pero, ¿qué pasa si necesitas una lógica diferente en tu programa? Por ejemplo, si su programa simula un análisis de ADN. Debe comparar el código de ADN de dos personas y determinar que son gemelos.

public class Man {

   int dnaCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.dnaCode = 1111222233;

       Man man2 = new Man();
       man2.dnaCode = 1111222233;

       System.out.println(man1 == man2);
   }
}
Salida de consola:

false
Es lógico que el resultado fuera el mismo (al fin y al cabo, no cambiamos nada), ¡pero ahora no estamos contentos con eso! Efectivamente, en la vida real, el análisis de ADN es garantía cien por cien de que estamos ante gemelos. Pero nuestro programa y operador ==nos dicen lo contrario. ¿Cómo podemos cambiar este comportamiento y asegurarnos de que si las pruebas de ADN coinciden, el programa producirá el resultado correcto? Para ello, se creó un método especial en Java: equals() .

Método igual() en Java

Al igual que el método toString()que analizamos anteriormente, equals() pertenece a la clase, Objectla clase más importante en Java, de la que se derivan todas las demás clases. Sin embargo, el propio equals() no cambiará el comportamiento de nuestro programa de ninguna manera:

public class Man {

   String dnaCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.dnaCode = "111122223333";

       Man man2 = new Man();
       man2.dnaCode = "111122223333";

       System.out.println(man1.equals(man2));
   }
}
Salida de consola:

false
Exactamente el mismo resultado, entonces ¿por qué se necesita este método? :/ Es sencillo. El hecho es que ahora usamos este método tal como está implementado en la propia clase Object. Y si entramos en el código de la clase Objecty miramos cómo se implementa este método y qué hace, veremos:

public boolean equals(Object obj) {
   return (this == obj);
}
¡Esta es la razón por la cual el comportamiento de nuestro programa no ha cambiado! Dentro del método equals() de la clase Objectse encuentra la misma comparación de referencia, ==. Pero el truco de este método es que podemos anularlo. ¡Anular significa escribir tu propio método equals() en nuestra clase Many hacer que se comporte como queremos! Ahora no estamos satisfechos de que el cheque man1.equals(man2)haga esencialmente lo mismo que man1 == man2. Esto es lo que haremos en esta situación:

public class Man {

   int dnaCode;

   public boolean equals(Man man) {
       return this.dnaCode ==  man.dnaCode;
   }

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.dnaCode = 1111222233;

       Man man2 = new Man();
       man2.dnaCode = 1111222233;

       System.out.println(man1.equals(man2));

   }
}
Salida de consola:

true
¡Un resultado completamente diferente! Al escribir nuestro propio método equals() en lugar del estándar, logramos el comportamiento correcto: ahora, si dos personas tienen el mismo código de ADN, el programa nos dice: “El análisis de ADN mostró que son gemelos” y devuelve verdadero. Al anular el método equals() en tus clases, puedes crear fácilmente la lógica de comparación de objetos necesaria. Hemos tocado la comparación de objetos sólo en términos generales. Todavía tendremos una gran conferencia separada sobre este tema por delante (puede leerla rápidamente ahora, si está interesado).

Comparación de cadenas en Java - Comparación de cadenas

¿Por qué tratamos las comparaciones de cadenas por separado de todo lo demás? Bueno, de hecho, las líneas en programación son una historia completamente diferente. En primer lugar, si tomamos todos los programas Java escritos por la humanidad, aproximadamente el 25% de los objetos que contienen están compuestos por ellos. Por tanto, este tema es muy importante. En segundo lugar, el proceso de comparar cadenas es realmente bastante diferente al de otros objetos. Veamos un ejemplo sencillo:

public class Main {

   public static void main(String[] args) {

       String s1 = "¡JavaRush es el mejor sitio para aprender Java!";
       String s2 = new String("¡JavaRush es el mejor sitio para aprender Java!");
       System.out.println(s1 == s2);
   }
}
Salida de consola:

false
¿Pero por qué falso? Las líneas son exactamente iguales, palabra por palabra :/ Puedes suponer: ¡ esto se debe a que el operador == compara referencias! Después de todo, s1tienen s2diferentes direcciones en la memoria. Si se le ocurrió esta idea, rehagamos nuestro ejemplo:

public class Main {

   public static void main(String[] args) {

       String s1 = "¡JavaRush es el mejor sitio para aprender Java!";
       String s2 = "¡JavaRush es el mejor sitio para aprender Java!";
       System.out.println(s1 == s2);
   }
}
Ahora también tenemos dos enlaces, pero el resultado ha cambiado a lo contrario: Salida de la consola:

true
¿Completamente confundido? :) Vamos a resolverlo. En realidad , el operador ==compara direcciones en la memoria. Esta regla siempre funciona y no hay que dudar de ella. Esto significa que si s1 == s2devuelve verdadero, estas dos cadenas tienen la misma dirección en la memoria. ¡Y efectivamente lo es! Es hora de familiarizarse con un área de memoria especial para almacenar cadenas: el grupo de cadenas ( String pool). Comparación de iguales y cadenas - 3El grupo de cadenas es un área para almacenar todos los valores de cadena que crea en su programa. ¿Para qué fue creado? Como se mencionó anteriormente, las cuerdas ocupan una gran parte de todos los objetos. En cualquier programa grande, se crean muchas líneas. Para ahorrar memoria, esto es lo que se necesita String Pool: se coloca allí una línea con el texto que necesita y, en el futuro, los enlaces recién creados se refieren a la misma área de memoria, no es necesario asignar memoria adicional cada vez. Cada vez que escribe String = “........”, el programa comprueba si hay una línea con dicho texto en el grupo de cadenas. Si lo hay, no se creará uno nuevo. Y el nuevo enlace apuntará a la misma dirección en el grupo de cadenas donde se almacena esta cadena. Por lo tanto, cuando escribimos en el programa

String s1 = "¡JavaRush es el mejor sitio para aprender Java!";
String s2 = "¡JavaRush es el mejor sitio para aprender Java!";
el enlace s2apunta exactamente al mismo lugar que s1. El primer comando creó una nueva línea en el grupo de cadenas con el texto que necesitábamos, y cuando llegó el segundo, simplemente se refería a la misma área de memoria que s1. Puedes hacer al menos 500 líneas más con el mismo texto, el resultado no cambiará. Detener. Pero, ¿por qué este ejemplo no nos funcionó antes?

public class Main {

   public static void main(String[] args) {

       String s1 = "¡JavaRush es el mejor sitio para aprender Java!";
       String s2 = new String("¡JavaRush es el mejor sitio para aprender Java!");
       System.out.println(s1 == s2);
   }
}
Creo que, intuitivamente, ya adivinas cuál es el motivo :) Intenta adivinar antes de seguir leyendo. Puede ver que estas dos líneas se crearon de manera diferente. Uno es con la ayuda del operador newy el segundo sin él. Ésta es precisamente la razón. El nuevo operador, al crear un objeto, le asigna por la fuerza una nueva área en la memoria . Y la línea creada con new, no termina en String Pool: se convierte en un objeto separado, incluso si su texto es exactamente el mismo que el de la misma línea de String Pool'a. Es decir, si escribimos el siguiente código:

public class Main {

   public static void main(String[] args) {

       String s1 = "¡JavaRush es el mejor sitio para aprender Java!";
       String s2 = "¡JavaRush es el mejor sitio para aprender Java!";
       String s3 = new String("¡JavaRush es el mejor sitio para aprender Java!");
   }
}
En la memoria se verá así: Comparación de iguales y cadenas - 4Y cada vez que se crea un nuevo objeto, newse asignará una nueva área en la memoria, ¡incluso si el texto dentro de las nuevas líneas es el mismo! Parece que hemos solucionado el problema del operador ==, pero ¿qué pasa con nuestro nuevo amigo, el método equals()?

public class Main {

   public static void main(String[] args) {

       String s1 = "¡JavaRush es el mejor sitio para aprender Java!";
       String s2 = new String("¡JavaRush es el mejor sitio para aprender Java!");
       System.out.println(s1.equals(s2));
   }
}
Salida de consola:

true
Interesante. Sabemos exactamente qué s1y s2señalamos diferentes áreas de la memoria. Pero, sin embargo, el método equals() dice que son iguales. ¿Por qué? ¿Recuerda que anteriormente dijimos que el método equals() se puede anular en su clase para que compare objetos de la manera que necesita? Eso es lo que hicieron con la clase String. Tiene un método igual a() anulado. Y no compara enlaces, sino la secuencia de caracteres en cadenas. Y si el texto en las cadenas es el mismo, no importa cómo se crearon y dónde se almacenan: en el grupo de cadenas o en un área de memoria separada. El resultado de la comparación será verdadero. Por cierto, Java le permite comparar cadenas correctamente sin distinguir entre mayúsculas y minúsculas. En una situación normal, si escribes una de las líneas, por ejemplo, en mayúsculas, el resultado de la comparación será falso:

public class Main {

   public static void main(String[] args) {

       String s1 = "¡JavaRush es el mejor sitio para aprender Java!";
       String s2 = new String("JAVARUSH - ЛУЧШИЙ САЙТ ДЛЯ ИЗУЧЕНИЯ JAVA!");
       System.out.println(s1.equals(s2));
   }
}
Salida de consola:

false
Para este caso, la clase Stringtiene un método equalsIgnoreCase(). Si lo principal en tu comparación es la secuencia de caracteres específicos, y no su caso, puedes usarlo. Por ejemplo, esto será útil al comparar dos direcciones de correo electrónico:

public class Main {

   public static void main(String[] args) {

       String address1 = "Moscú, calle Académico Korolev, 12";
       String address2 = new String("Г. МОСКВА, УЛ. АКАДЕМИКА КОРОЛЕВА, ДОМ 12");
       System.out.println(address1.equalsIgnoreCase(address2));
   }
}
En este caso, es obvio que estamos hablando de la misma dirección, por lo que utilizar el método equalsIgnoreCase()será la decisión correcta.

Método String.intern()

La clase Stringtiene otro método complicado: intern(); El método intern()funciona directamente con String Pool'om. Si llama a un método intern()en una cadena,:
  • Mira para ver si hay una cadena con este texto en el grupo de cadenas.
  • Si lo hay, devuelve un enlace al mismo en el grupo.
  • De lo contrario, coloca una línea con este texto en el grupo de cadenas y le devuelve un enlace.
Al aplicar el método intern()a la referencia de cadena que se creó mediante new, podemos compararla con la referencia de cadena de String Pool'a mediante ==.

public class Main {

   public static void main(String[] args) {

       String s1 = "¡JavaRush es el mejor sitio para aprender Java!";
       String s2 = new String("¡JavaRush es el mejor sitio para aprender Java!");
       System.out.println(s1 == s2.intern());
   }
}
Salida de consola:

true
Anteriormente, cuando los comparamos sin intern(), el resultado era falso. Ahora el método intern()comprobó si había una línea con el texto "JavaRush - ¡el mejor sitio para aprender Java!" en el grupo de cuerdas. Por supuesto que está ahí: lo creamos cuando escribimos

String s1 = "¡JavaRush es el mejor sitio para aprender Java!";
Se comprobó que la referencia s1y la referencia devuelta por el método s2.intern()apuntan a la misma área en la memoria, y, por supuesto, lo hacen :) Para resumir, recuerde y use la regla principal: Para comparar cadenas, use SIEMPRE el método igual() ¡método! Al comparar cadenas, casi siempre te refieres a comparar su texto, no enlaces, áreas de memoria, etc. El método equals() hace exactamente lo que necesitas. Aquí te dejamos algunos enlaces para que estudies por tu cuenta:
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION