CodeGym/Blog Java/Random-ES/Comparar comparaciones de cadenas e iguales en Java
Autor
Milan Vucic
Programming Tutor at Codementor.io

Comparar comparaciones de cadenas e iguales en Java

Publicado en el grupo Random-ES
¡Hola! Hoy hablaremos sobre un tema muy importante e interesante, a saber, comparar objetos con objetos (Comparar cadenas e iguales). Entonces, en Java, ¿cuándo exactamente el objeto A sería igual al objeto B ? Intentemos 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 la consola: falso Espere, deténgase. ¿Por qué estos dos autos no son iguales? Les asignamos las mismas propiedades, pero el resultado de la comparación es falso. La respuesta es simple. El operador == compara referencias de objetos, no propiedades de objetos. Dos objetos podrían incluso tener 500 campos con valores idénticos, pero compararlos aún daría falso. Después de todo, las referencias a car1 y car2apuntar a dos objetos diferentes, es decir, a dos direcciones diferentes. Imagina una situación en la que estás comparando personas. Ciertamente, en algún lugar del mundo hay una persona que comparte su mismo nombre, color de ojos, edad, altura, color de cabello, etc. Eso los hace similares en muchos aspectos, pero aún no son gemelos, y obviamente no lo son. la misma persona.
Iguales y comparaciones de cadenas - 2
El operador == usa aproximadamente esta misma lógica cuando lo usamos para comparar dos objetos. Pero, ¿qué sucede si necesita que su programa use una lógica diferente? Por ejemplo, suponga que su programa realiza análisis de ADN. Compara el código genético de dos personas y determina si son gemelos.
public class Man {

   int geneticCode;

   public static void main(String[] args) {

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

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

       System.out.println(man1 == man2);
   }
}
Salida de la consola: falso Obtenemos el mismo resultado lógico (porque no cambiamos mucho), ¡pero ahora esa lógica no es buena! Después de todo, en la vida real, el análisis de ADN debería darnos una garantía del 100% de que tenemos gemelos frente a nosotros. Pero nuestro programa y el operador == nos dicen lo contrario. ¿Cómo cambiamos este comportamiento y nos aseguramos de que el programa genere el resultado correcto cuando el ADN coincida? Java tiene un método especial para esto: equals() . Al igual que el método toString() , que discutimos anteriormente, equals() pertenece a la clase Object , la clase más importante en Java, la clase de la que derivan todas las demás clases. Pero igual()no cambia el comportamiento de nuestro programa por sí mismo:
public class Man {

   String geneticCode;

   public static void main(String[] args) {

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

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

       System.out.println(man1.equals(man2));
   }
}
Salida de la consola: falso Exactamente el mismo resultado, entonces, ¿para qué necesitamos este método? :/ Todo es simple. El problema aquí es que actualmente estamos usando este método tal como está implementado en la clase Object . Y si vamos al código de la clase Object y miramos la implementación del método, esto es lo que veremos:
public boolean equals(Object obj) {
   return (this == obj);
}
¡Esa es la razón por la cual el comportamiento del programa no ha cambiado! El mismo operador == (que compara referencias) se usa dentro del método equals() de la clase Object . Pero el truco con este método es que podemos anularlo. Anular significa escribir su propio método equals() en nuestra clase Man , dándole el comportamiento que necesitamos. Actualmente, no nos gusta el hecho de que man1.equals(man2) sea esencialmente equivalente a 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 la consola: verdadero ¡ Ahora obtenemos un resultado completamente diferente! Al escribir nuestro propio método equals() y usarlo en lugar del estándar, hemos producido el comportamiento correcto: ahora, si dos personas tienen el mismo ADN, el programa informa que "el análisis de ADN ha demostrado que son gemelos" y devuelve verdadero. Al anular el método equals() en sus clases, puede crear fácilmente cualquier lógica de comparación de objetos que necesite. De hecho, acabamos de tocar la comparación de objetos. Delante de nosotros, todavía hay una gran lección independiente sobre este tema (puede hojearla ahora si está interesado).

Comparando cadenas en Java

¿Por qué consideramos las comparaciones de cadenas por separado de todo lo demás? La realidad es que las cadenas son un tema por derecho propio en la programación. Primero, si toma todos los programas Java que se han escrito, encontrará que alrededor del 25% de los objetos en ellos son cadenas. Entonces este tema es muy importante. En segundo lugar, el proceso de comparar cadenas es realmente muy diferente al de otros objetos. Considere un ejemplo simple:
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2);
   }
}
Salida de la consola: falso Pero, ¿por qué obtuvimos falso? Después de todo, las cadenas son exactamente iguales, palabra por palabra:/ Puede que hayas adivinado la razón: ¡ es porque el operador == compara referencias ! Claramente, s1 y s2 tienen diferentes direcciones en la memoria. Si pensaste en eso, reelaboremos nuestro ejemplo:
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       System.out.println(s1 == s2);
   }
}
Ahora volvemos a tener dos referencias, pero el resultado es exactamente lo contrario: Salida de la consola: verdadero ¿Confundido sin poder hacer nada? Averigüemos qué está pasando. El operador == realmente compara direcciones de memoria. Esto siempre es cierto y no necesitas dudarlo. Eso significa que si s1 == s2 devuelve verdadero, entonces estas dos cadenas tienen la misma dirección. ¡Y de hecho esto es cierto! Es hora de presentarle un área especial de la memoria para almacenar cadenas: el grupo de cadenas
Iguales y comparaciones de cadenas - 3
El grupo de cadenas es un área para almacenar todos los valores de cadena que crea en su programa. ¿Por qué fue creado? Como dijimos antes, las cadenas representan un gran porcentaje de todos los objetos. Cualquier programa grande crea muchas cadenas. El grupo de cadenas se creó para ahorrar memoria: las cadenas se colocan allí y luego las cadenas creadas posteriormente se refieren a la misma área de memoria; no es necesario asignar memoria adicional cada vez. Cada vez que escribe String = "........" el programa verifica si hay una cadena idéntica en el grupo de cadenas. Si lo hay, entonces no se creará una nueva cadena. Y la nueva referencia apuntará a la misma dirección en el conjunto de cadenas (donde se encuentra la cadena idéntica). Así que cuando escribimos
String s1 = "CodeGym is the best website for learning Java!";
String s2 = "CodeGym is the best website for learning Java!";
s2 apunta al mismo lugar que s1 . La primera declaración crea una nueva cadena en el grupo de cadenas. La segunda declaración simplemente se refiere a la misma área de memoria que s1 . Podría hacer otras 500 cadenas idénticas y el resultado no cambiaría. Espera un minuto. Si eso es cierto, ¿por qué no funcionó este ejemplo antes?
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2);
   }
}
Creo que tu intuición ya te ha dicho la razón =) Intenta adivinar antes de seguir leyendo. Puede ver que estas dos cadenas se declararon de diferentes maneras. Uno con el nuevo operador y el otro sin él. Aquí radica la razón. Cuando el operador new se usa para crear un objeto, asigna forzosamente una nueva área de memoria para el objeto. Y una cadena creada con new no termina en el grupo de cadenas: se convierte en un objeto separado, incluso si su texto coincide perfectamente con una cadena en el grupo de cadenas. Es decir, si escribimos el siguiente código:
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       String s3 = new String("CodeGym is the best website for learning Java!");
   }
}
En la memoria, se ve así:
Iguales y comparaciones de cadenas - 4
Y cada vez que crea un nuevo objeto usando new , se asigna una nueva área de memoria, ¡incluso si el texto dentro de la nueva cadena es el mismo! Parece que hemos descubierto el operador == . Pero, ¿qué pasa con nuestro nuevo conocido, el método equals() ?
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1.equals(s2));
   }
}
Salida de la consola: verdadero Interesante. Estamos seguros de que s1 y s2 apuntan a diferentes áreas de la memoria. Pero el método equals() todavía nos dice que son iguales. ¿Por qué? ¿Recuerdas que dijimos anteriormente que el método equals() podría anularse para comparar objetos como queramos? Eso es justo lo que han hecho con la clase String . Anula los iguales ()método. Y en lugar de comparar referencias, compara la secuencia de caracteres en las cadenas. Si el texto es el mismo, entonces no importa cómo se crearon o dónde se almacenaron: si en el grupo de cadenas o en un área separada de la memoria. El resultado de la comparación será verdadero. Por cierto, Java le permite realizar comparaciones de cadenas que no distinguen entre mayúsculas y minúsculas. Normalmente, si una de las cadenas tiene todas las letras mayúsculas, el resultado de la comparación será falso:
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CODEGYM IS THE BEST WEBSITE FOR LEARNING JAVA!");
       System.out.println(s1.equals(s2));
   }
}
Salida de la consola: falso Para las comparaciones que no distinguen entre mayúsculas y minúsculas, la clase String tiene el método equalsIgnoreCase() . Puede usarlo si solo le importa comparar la secuencia de caracteres específicos en lugar de las mayúsculas y minúsculas. Por ejemplo, esto podría ser útil al comparar dos direcciones:
public class Main {

   public static void main(String[] args) {

       String address1 = "2311 Broadway Street, San Francisco";
       String address2 = new String("2311 BROADWAY STREET, SAN FRANCISCO");
       System.out.println(address1.equalsIgnoreCase(address2));
   }
}
En este caso, obviamente estamos hablando de la misma dirección, por lo que tiene sentido usar el método equalsIgnoreCase() .

El método String.intern()

La clase String tiene otro método complicado: intern() ; El método interno() funciona directamente con el grupo de cadenas. Si llama al método interno () en alguna cadena:
  • Comprueba si hay una cadena coincidente en el grupo de cadenas
  • Si lo hay, devuelve la referencia a la cadena en el grupo
  • Si no, agrega la cadena al grupo de cadenas y devuelve una referencia a ella.
Después de usar el método intern() en una referencia de cadena obtenida con new , podemos usar el operador == para compararla con una referencia de cadena del grupo de cadenas.
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2.intern());
   }
}
Salida de la consola: verdadero Cuando comparamos estas cadenas anteriormente sin intern() , el resultado fue falso. Ahora el método interno() comprueba si la cadena "¡CodeGym es el mejor sitio para aprender Java!" está en el grupo de cuerdas. Por supuesto que lo es: lo creamos con
String s1 = "CodeGym is the best website for learning Java!";
Comprobamos si s1 y la referencia devuelta por s2.intern() apuntan a la misma área de memoria. Y, por supuesto, lo hacen :) En resumen, memoriza y aplica esta importante regla: ¡SIEMPRE usa el método equals() para comparar cadenas! Cuando comparamos cadenas, casi siempre queremos comparar sus caracteres en lugar de referencias, áreas de memoria o cualquier otra cosa. El método equals() hace exactamente lo que necesita. Para reforzar lo que aprendió, le sugerimos que vea una lección en video de nuestro Curso de Java
Comentarios
  • Populares
  • Nuevas
  • Antiguas
Debes iniciar sesión para dejar un comentario
Esta página aún no tiene comentarios