Comparaciones de cadenas en Java

En Java, la Stringclase encapsula una matriz de char. En pocas palabras, Stringes una serie de caracteres que se utilizan para componer palabras, oraciones o cualquier otro dato que desee.

La encapsulación es uno de los conceptos más poderosos de la programación orientada a objetos. Debido a la encapsulación, no necesita saber cómo funciona la clase String; solo necesita saber qué métodos usar en su interfaz.

Cuando observa la Stringclase en Java, puede ver cómo charse encapsula la matriz de :

 public String(char value[]) { this(value, 0, value.length, null); } 

Para comprender mejor la encapsulación, considere un objeto físico: un automóvil. ¿Necesita saber cómo funciona el coche bajo el capó para poder conducirlo? Por supuesto que no, pero necesita saber qué hacen las interfaces del automóvil: cosas como el acelerador, los frenos y el volante. Cada una de estas interfaces admite ciertas acciones: acelerar, frenar, girar a la izquierda, girar a la derecha. Es lo mismo en la programación orientada a objetos.

Mi primer blog de la serie Java Challengers introdujo la sobrecarga de métodos, que es una técnica que la Stringclase usa ampliamente. La sobrecarga puede hacer que sus clases sean realmente flexibles, que incluyen String:

 public String(String original) {} public String(char value[], int offset, int count) {} public String(int[] codePoints, int offset, int count) {} public String(byte bytes[], int offset, int length, String charsetName) {} // And so on…... 

En lugar de intentar comprender cómo funciona la Stringclase, este Java Challenger lo ayudará a comprender qué hace y cómo usarlo en su código.

¿Qué es un grupo de cuerdas?

Stringes posiblemente la clase más utilizada en Java. Si se crea un nuevo objeto en el montón de memoria cada vez que usamos un String, desperdiciaríamos mucha memoria. El Stringgrupo resuelve este problema almacenando solo un objeto para cada Stringvalor, como se muestra a continuación.

Rafael Chinelato Del Nero

Aunque creamos una Stringvariable para el Dukee JuggyStrings, sólo dos objetos son creados y almacenados en el montón de memoria. Para obtener una prueba, consulte el siguiente ejemplo de código. (Recuerde que el ==operador " " en Java se usa para comparar dos objetos y determinar si son iguales).

 String juggy = "Juggy"; String anotherJuggy = "Juggy"; System.out.println(juggy == anotherJuggy); 

Este código regresará trueporque los dos Stringapuntan al mismo objeto en el Stringgrupo. Sus valores son los mismos.

Una excepción: el operador 'nuevo'

Ahora mire este código: se ve similar al ejemplo anterior, pero hay una diferencia.

 String duke = new String("duke"); String anotherDuke = new String("duke"); System.out.println(duke == anotherDuke); 

Según el ejemplo anterior, podría pensar que este código volvería true, pero en realidad es false. Agregar el newoperador fuerza la creación de un nuevo Stringen el montón de memoria. Por lo tanto, la JVM creará dos objetos diferentes.

Métodos nativos

Un método nativo en Java es un método que se compilará utilizando el lenguaje C, generalmente con el propósito de manipular la memoria y optimizar el rendimiento.

Grupos de cadenas y el método intern ()

Para almacenar un Stringen la Stringpiscina, utilizamos una técnica llamada Stringinternación . Esto es lo que Javadoc nos dice sobre el intern()método:

 /** * Returns a canonical representation for the string object. * * A pool of strings, initially empty, is maintained privately by the * class {@code String}. * * When the intern method is invoked, if the pool already contains a * string equal to this {@code String} object as determined by * the {@link #equals(Object)} method, then the string from the pool is * returned. Otherwise, this {@code String} object is added to the * pool and a reference to this {@code String} object is returned. * * It follows that for any two strings {@code s} and {@code t}, * {@code s.intern() == t.intern()} is {@code true} * if and only if {@code s.equals(t)} is {@code true}. * * All literal strings and string-valued constant expressions are * interned. String literals are defined in section 3.10.5 of the * The Java™ Language Specification. * * @returns a string that has the same contents as this string, but is * guaranteed to be from a pool of unique strings. * @jls 3.10.5 String Literals */ public native String intern(); 

El intern()método se utiliza para almacenar correos Stringelectrónicos en una Stringpiscina. Primero, verifica si el Stringque ha creado ya existe en el grupo. Si no, crea una nueva Stringen la piscina. Detrás de escena, la lógica de la Stringagrupación se basa en el patrón Flyweight.

Ahora, observe lo que sucede cuando usamos la newpalabra clave para forzar la creación de dos Strings:

 String duke = new String("duke"); String duke2 = new String("duke"); System.out.println(duke == duke2); // The result will be false here System.out.println(duke.intern() == duke2.intern()); // The result will be true here 

A diferencia del ejemplo anterior con la newpalabra clave, en este caso la comparación resulta cierta. Eso es porque el uso del intern()método asegura que los Stringcorreos electrónicos se almacenarán en el grupo.

Igual al método con la clase String

El equals()método se utiliza para verificar si el estado de dos clases de Java es el mismo. Porque equals()es de la Objectclase, cada clase de Java lo hereda. Pero el equals()método debe anularse para que funcione correctamente. Por supuesto, Stringanula equals().

Echar un vistazo:

 public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String aString = (String)anObject; if (coder() == aString.coder()) { return isLatin1() ? StringLatin1.equals(value, aString.value) : StringUTF16.equals(value, aString.value); } } return false; } 

Como puede ver, el estado del Stringvalor de la clase tiene que ser equals()y no la referencia del objeto. No importa si la referencia del objeto es diferente; Stringse comparará el estado de la voluntad.

Métodos de cadena más comunes

Solo hay una última cosa que necesita saber antes de aceptar el Stringdesafío de la comparación. Considere estos métodos comunes de la Stringclase:

 // Removes spaces from the borders trim() // Gets a substring by indexes substring(int beginIndex, int endIndex) // Returns the characters length of the String length() // Replaces String, regex can be used. replaceAll(String regex, String replacement) // Verifies if there is a specified CharSequence in the String contains(CharSequences) 

¡Acepta el desafío de comparación de cadenas!

Probemos lo que ha aprendido sobre la Stringclase en un desafío rápido.

Para este desafío, comparará varios Strings utilizando los conceptos que hemos explorado. Mirando el código a continuación, ¿puede determinar el valor final de cada variable de resultados ?

 public class ComparisonStringChallenge { public static void main(String... doYourBest) { String result = ""; result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1"; result += "flexibleCode" == "flexibleCode" ? "2" : "3"; result += new String("doYourBest") == new String("doYourBest") ? "4" : "5"; result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7"; result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9"; System.out.println(result); } } 

¿Qué salida representa el valor final de la variable de resultados?

A : 02468

B : 12469

C : 12579

D : 12568

Comprueba tu respuesta aquí.

¿Lo que acaba de suceder? Comprender el comportamiento de las cadenas

En la primera línea del código, vemos:

 result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1"; 

Aunque Stringserá el mismo después de trim()invocar el método, String“ powerfulcode “al principio era diferente. En este caso la comparación es false, porque cuando el trim()método quita espacios de los bordes fuerza la creación de un nuevo Stringcon el nuevo operador.

A continuación, vemos:

 result += "flexibleCode" == "flexibleCode" ? "2" : "3"; 

No mystery here, the Strings are the same in the String pool. This comparison returns true.

Next, we have:

 result += new String("doYourBest") == new String("doYourBest") ? "4" : "5"; 

Using the new reserved keyword forces the creation of two new Strings, whether they are equal or not. In this case the comparison will be false even if the String values are the same.

Next is:

 result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7"; 

Because we’ve used the equals() method, the value of the String will be compared and not the object instance. In that case, it doesn’t matter if the objects are different because the value is being compared. This comparison returns true.

Finally, we have:

 result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9"; 

As you’ve seen before, the intern() method puts the String in the String pool. Both Strings point to the same object, so in this case the comparison is true.

Video challenge! Debugging String comparisons

Debugging is one of the easiest ways to fully absorb programming concepts while also improving your code. In this video you can follow along while I debug and explain the Java Strings challenge:

Common mistakes with Strings

It can be difficult to know if two Strings are pointing to the same object, especially when the Strings contain the same value. It helps to remember that using the reserved keyword new always results in a new object being created in memory, even if the values are the same.

Using String methods to compare Object references can also be tricky. The key is, if the method changes something in the String, the object references will be different.

A few examples to help clarify:

 System.out.println("duke".trim() == "duke".trim());; 

This comparison will be true because the trim() method does not generate a new String.

 System.out.println(" duke".trim() == "duke".trim()); 

In this case, the first trim() method will generate a new String because the method will execute its action, so the references will be different.

Finally, when trim() executes its action, it creates a new String:

 // Implementation of the trim method in the String class new String(Arrays.copyOfRange(val, index, index + len), LATIN1); 

What to remember about Strings

  • Strings are immutable, so a String’s state can’t be changed.
  • To conserve memory, the JVM keeps Strings in a String pool. When a new String is created, the JVM checks its value and points it to an existing object. If there is no String with that value in the pool, then the JVM creates a new String.
  • El ==operador compara la referencia del objeto. El uso del equals()método compara el valor de String. La misma regla se aplicará a todos los objetos.
  • Al usar el newoperador, se Stringcreará un nuevo en el Stringgrupo incluso si hay uno Stringcon el mismo valor.

 

Clave de respuesta

La respuesta a este desafío de Java es la Opción D. El resultado sería 12568.

Esta historia, "Comparaciones de cadenas en Java", fue publicada originalmente por JavaWorld.