¿Cuándo deberíamos usar el método interno de los literales String en String?

Según String # intern () , se supone que el método intern devuelve la cadena del conjunto de cadenas si la cadena se encuentra en el grupo de cadenas; de lo contrario, se agregará un nuevo objeto de cadena en el grupo de cadenas y se devolverá la referencia de esta cadena.

Así que intenté esto:

 String s1 = "Rakesh"; String s2 = "Rakesh"; String s3 = "Rakesh".intern(); if ( s1 == s2 ){ System.out.println("s1 and s2 are same"); // 1. } if ( s1 == s3 ){ System.out.println("s1 and s3 are same" ); // 2. } 

Esperaba que s1 and s3 are same se imprimirán ya que s3 está internado, y s1 and s2 are same y no se imprimirán. Pero el resultado es: ambas líneas están impresas. Eso significa que, por defecto, las constantes de cadena están intercaladas. Pero si es así, ¿por qué necesitamos el método intern ? En otras palabras, ¿cuándo deberíamos usar este método?

Java automáticamente interna literales de cadena. Esto significa que, en muchos casos, el operador == parece funcionar para cadenas de la misma forma que lo hace para las entradas u otros valores primitivos.

Como el internamiento es automático para literales de cadena, el método intern() se usará en cadenas construidas con new String()

Usando tu ejemplo:

 String s1 = "Rakesh"; String s2 = "Rakesh"; String s3 = "Rakesh".intern(); String s4 = new String("Rakesh"); String s5 = new String("Rakesh").intern(); if ( s1 == s2 ){ System.out.println("s1 and s2 are same"); // 1. } if ( s1 == s3 ){ System.out.println("s1 and s3 are same" ); // 2. } if ( s1 == s4 ){ System.out.println("s1 and s4 are same" ); // 3. } if ( s1 == s5 ){ System.out.println("s1 and s5 are same" ); // 4. } 

volverá:

 s1 and s2 are same s1 and s3 are same s1 and s5 are same 

Consulte JavaTechniques “String Equality and Interning” para obtener más información.

En un proyecto reciente, algunas enormes estructuras de datos se configuraron con datos que se leyeron desde una base de datos (y, por lo tanto, no constantes / literales) pero con una gran cantidad de duplicaciones. Era una aplicación bancaria, y cosas como los nombres de un conjunto modesto (tal vez 100 o 200) corporaciones aparecieron por todas partes. Las estructuras de datos ya eran grandes, y si todos esos nombres corporativos hubieran sido objetos únicos, habrían desbordado la memoria. En cambio, todas las estructuras de datos tenían referencias a los mismos 100 o 200 objetos String, ahorrando así mucho espacio.

Otra pequeña ventaja de las cadenas internas es que == puede usarse (¡con éxito!) Para comparar cadenas si se garantiza que todas las cadenas implicadas serán intercaladas. Además de la syntax más ligera, esta es también una mejora del rendimiento. Pero como otros han señalado, hacer esto conlleva un gran riesgo de introducir errores de progtwigción, por lo que esto debería hacerse solo como una medida despiadada de último recurso.

La desventaja es que internar un String toma más tiempo que simplemente tirarlo al heap, y que el espacio para Strings internados puede ser limitado, dependiendo de la implementación de Java. Es mejor hacerlo cuando se trata de un número razonablemente conocido de cadenas con muchas duplicaciones.

Quiero agregar mis 2 centavos al uso de == con cadenas internas.

Lo primero que hace String.equals es this==object .

Entonces, aunque hay una ganancia de rendimiento minúscula (no se está llamando a un método), desde el punto de vista del sustentador el uso de == es una pesadilla, porque algunas cadenas internas tienden a convertirse en no internadas.

Así que sugiero no confiar en un caso especial de == para cadenas internas, pero siempre use equals como Gosling.

EDITAR: internado convirtiéndose en no internado:

 V1.0 public class MyClass { private String reference_val; ... private boolean hasReferenceVal ( final String[] strings ) { for ( String s : strings ) { if ( s == reference_val ) { return true; } } return false; } private void makeCall ( ) { final String[] interned_strings = { ... init with interned values ... }; if ( hasReference( interned_strings ) ) { ... } } } 

En la versión 2.0, el hasReferenceVal decidió hacer público el valor de hasReferenceVal , sin entrar en muchos detalles que espera una serie de cadenas internas.

 V2.0 public class MyClass { private String reference_val; ... public boolean hasReferenceVal ( final String[] strings ) { for ( String s : strings ) { if ( s == reference_val ) { return true; } } return false; } private void makeCall ( ) { final String[] interned_strings = { ... init with interned values ... }; if ( hasReference( interned_strings ) ) { ... } } } 

Ahora tiene un error, que puede ser muy difícil de encontrar, porque en la mayoría de los casos la matriz contiene valores literales, y algunas veces se usa una cadena no literal. Si se usaron equals lugar de == entonces hasReferenceVal seguiría funcionando. Una vez más, la ganancia de rendimiento es minúscula, pero el costo de mantenimiento es alto.

Los literales y las constantes de cadena están intercalados por defecto. Es decir, "foo" == "foo" (declarado por los literales String), pero new String("foo") != new String("foo") .

debe distinguir dos períodos que son el tiempo de comstackción y el tiempo de ejecución. Por ejemplo:

 //example 1 "test" == "test" // --> true "test" == "te" + "st" // --> true //example 2 "test" == "!test".substring(1) // --> false "test" == "!test".substring(1).intern() // --> true 

por un lado, en el ejemplo 1, encontramos que los resultados son todos verdaderos, porque en el tiempo de comstackción, el jvm pondrá la “prueba” al conjunto de cadenas literales, si el jvm encuentra “prueba”, entonces usará el existente, en el ejemplo 1, las cadenas de “prueba” apuntan a la misma dirección de memoria, por lo que el ejemplo 1 devolverá verdadero. por otro lado, en el ejemplo 2, el método de subcadena () se ejecuta en el tiempo de ejecución, en el caso de “prueba” == “! prueba” .substring (1), el grupo creará dos objetos de cadena, ” test “y”! test “, por lo que son diferentes objetos de referencia, por lo que este caso arrojará false, en el caso de” test “==”! test “.substring (1) .intern (), el método de pasante ( ) pondrá “”! test “.substring (1)” en el conjunto de cadenas literales, por lo que en este caso, son los mismos objetos de referencia, por lo que se devolverá verdadero.

http://en.wikipedia.org/wiki/String_interning

El interinato de cadena es un método para almacenar solo una copia de cada valor de cadena distinto, que debe ser inmutable. Las cadenas de internados hacen que algunas tareas de procesamiento de cadenas sean más eficientes en tiempo o espacio a costa de requerir más tiempo cuando la cadena se crea o se interna. Los valores distintos se almacenan en un grupo interno de cadena.

Las cadenas internas evitan cadenas duplicadas. Interning ahorra RAM a expensas de más tiempo de CPU para detectar y reemplazar cadenas duplicadas. Solo hay una copia de cada cadena que ha sido internada, sin importar cuántas referencias la señalen. Dado que las cadenas son inmutables, si dos métodos diferentes usan incidentalmente la misma cadena, pueden compartir una copia de la misma cadena. El proceso de conversión de cadenas duplicadas a compartidas se denomina interning.String.intern () le proporciona la dirección de la cadena maestra canónica. Puede comparar cadenas internas con simple == (que compara punteros) en lugar de iguales que compara los caracteres de la cadena uno por uno. Como las cadenas son inmutables, el proceso interno es libre de ahorrar aún más espacio, por ejemplo, al no crear un literal de cadena separado para “pot” cuando existe como una subcadena de algún otro literal como “hipopótamo”.

Para ver más http://mindprod.com/jgloss/interned.html

 String s1 = "Anish"; String s2 = "Anish"; String s3 = new String("Anish"); /* * When the intern method is invoked, if the pool already contains a * string equal to this String object as determined by the * method, then the string from the pool is * returned. Otherwise, this String object is added to the * pool and a reference to this String object is returned. */ String s4 = new String("Anish").intern(); if (s1 == s2) { System.out.println("s1 and s2 are same"); } if (s1 == s3) { System.out.println("s1 and s3 are same"); } if (s1 == s4) { System.out.println("s1 and s4 are same"); } 

SALIDA

 s1 and s2 are same s1 and s4 are same 
 String p1 = "example"; String p2 = "example"; String p3 = "example".intern(); String p4 = p2.intern(); String p5 = new String(p3); String p6 = new String("example"); String p7 = p6.intern(); if (p1 == p2) System.out.println("p1 and p2 are the same"); if (p1 == p3) System.out.println("p1 and p3 are the same"); if (p1 == p4) System.out.println("p1 and p4 are the same"); if (p1 == p5) System.out.println("p1 and p5 are the same"); if (p1 == p6) System.out.println("p1 and p6 are the same"); if (p1 == p6.intern()) System.out.println("p1 and p6 are the same when intern is used"); if (p1 == p7) System.out.println("p1 and p7 are the same"); 

Cuando se crean dos cadenas de forma independiente, intern() permite compararlas y también le ayuda a crear una referencia en el grupo de cadenas si la referencia no existía antes.

Cuando utiliza String s = new String(hi) , java crea una nueva instancia de la cadena, pero cuando usa String s = "hi" , java comprueba si hay una instancia de la palabra “hi” en el código o no y si existe, simplemente devuelve la referencia.

Dado que la comparación de cadenas se basa en la referencia, intern() ayuda a crear una referencia y le permite comparar el contenido de las cadenas.

Cuando utiliza el intern() en el código, borra el espacio utilizado por la cadena que hace referencia al mismo objeto y simplemente devuelve la referencia del mismo objeto ya existente en la memoria.

Pero en el caso de p5 cuando estás usando:

 String p5 = new String(p3); 

Solo se copian los contenidos de p3 y p5 se crea nuevamente. Entonces no está internado .

Entonces la salida será:

 p1 and p2 are the same p1 and p3 are the same p1 and p4 are the same p1 and p6 are the same when intern is used p1 and p7 are the same 

Aprender Java String Intern – una vez por todas

Las cadenas en java son objetos inmutables por diseño. Por lo tanto, dos objetos de cadena, incluso con el mismo valor, serán diferentes objetos por defecto. Sin embargo, si deseamos ahorrar memoria, podemos indicar que usemos la misma memoria mediante un concepto llamado cadena interna.

Las siguientes reglas lo ayudarán a entender el concepto en términos claros:

  1. La clase String mantiene un grupo interno que inicialmente está vacío. Este grupo debe garantizar que contenga objetos de cadena con solo valores únicos.
  2. Todos los literales de cadena que tengan el mismo valor deben considerarse el mismo objeto de ubicación de memoria porque de lo contrario no tienen ninguna noción de distinción. Por lo tanto, todos los literales con el mismo valor harán una sola entrada en el grupo interno y se referirán a la misma ubicación de memoria.
  3. La concatenación de dos o más literales también es un literal. (Por lo tanto la regla # 2 será aplicable para ellos)
  4. Cada cadena creada como objeto (es decir, por cualquier otro método, excepto como literal) tendrá diferentes ubicaciones de memoria y no hará ninguna entrada en el grupo interno
  5. La concatenación de literales con non-literales hará que no sea literal. Por lo tanto, el objeto resultante tendrá una nueva ubicación de memoria y NO hará una entrada en el grupo interno.
  6. Al invocar el método interno en un objeto de cadena, se crea un nuevo objeto que ingresa al grupo interno o se devuelve un objeto existente del grupo que tiene el mismo valor. La invocación de cualquier objeto que no está en el grupo interno, NO mueve el objeto al grupo. Más bien crea otro objeto que ingresa al grupo.

Ejemplo:

 String s1=new String (“abc”); String s2=new String (“abc”); If (s1==s2) //would return false by rule #4 If (“abc” == “a”+”bc” ) //would return true by rules #2 and #3 If (“abc” == s1 ) //would return false by rules #1,2 and #4 If (“abc” == s1.intern() ) //would return true by rules #1,2,4 and #6 If ( s1 == s2.intern() ) //wound return false by rules #1,4, and #6 

Nota: Los casos de motivación para el interno de cuerdas no se discuten aquí. Sin embargo, el ahorro de memoria definitivamente será uno de los principales objectives.

  public static void main(String[] args) { // TODO Auto-generated method stub String s1 = "test"; String s2 = new String("test"); System.out.println(s1==s2); //false System.out.println(s1==s2.intern()); //true --> because this time compiler is checking from string constant pool. } 

Las cadenas internas evitan cadenas duplicadas. Interning ahorra RAM a expensas de más tiempo de CPU para detectar y reemplazar cadenas duplicadas. Solo hay una copia de cada cadena que ha sido internada, sin importar cuántas referencias la señalen.

Aunque Java automáticamente interna todas las cadenas por defecto, recuerde que solo tenemos que internar cadenas cuando no son constantes, y queremos poder compararlas rápidamente con otras cadenas internas. El método interno () se debe usar en cadenas construidas con una cadena nueva () para compararlas con == operador.

public class TestString {

 public static void main(String[] args) { String s1 = "Test"; String s2 = "Test"; String s3 = new String("Test"); final String s4 = s3.intern(); System.out.println(s1 == s2); System.out.println(s2 == s3); System.out.println(s3 == s4); System.out.println(s1 == s3); System.out.println(s1 == s4); System.out.println(s1.equals(s2)); System.out.println(s2.equals(s3)); System.out.println(s3.equals(s4)); System.out.println(s1.equals(s4)); System.out.println(s1.equals(s3)); } 

}

//Salida

cierto

falso

falso

falso

cierto

cierto

cierto

cierto

cierto

cierto

¿Por qué no se pueden usar literales de cadena en los lugares donde se requiere el uso interno? El uso literal de cadena de forma predeterminada reutilizará los literales de cadena existentes. Entonces, ¿por qué necesitamos crear un nuevo String (“algo”) .intern () en lugar de solo asignar “algo”?

El método string intern () se utiliza para crear una copia exacta del objeto de la cadena de montón en el grupo de constante de cadena. Los objetos de cadena en el grupo de constante de cadena se internan automáticamente, pero los objetos de cadena en el montón no lo son. El uso principal de la creación de pasantes es guardar el espacio de la memoria y realizar una comparación más rápida de los objetos de cadena.

Fuente: ¿Qué es el interno de cuerdas en java?

Como dijo, ese método string intern() primero encontrará desde el conjunto de cadenas, si lo encuentra, devolverá el objeto que apunta a eso, o agregará un nuevo String en el grupo.

  String s1 = "Hello"; String s2 = "Hello"; String s3 = "Hello".intern(); String s4 = new String("Hello"); System.out.println(s1 == s2);//true System.out.println(s1 == s3);//true System.out.println(s1 == s4.intern());//true 

El s1 y el s2 son dos objetos que apuntan al grupo de cadenas “Hello”, y con "Hello".intern() encontrará que s1 y s2 . Por lo tanto, "s1 == s3" devuelve verdadero, así como a s3.intern() .