Hay dos formas de creación de objetos de cadena en Java, una es una forma literal, como String str = "droid"; y la otra es usar new, un método estándar para construir objetos, como String str = new String( "droid");, estos dos métodos se utilizan a menudo al escribir código, especialmente el método literal. Sin embargo, en realidad existen algunas diferencias en el rendimiento y el uso de memoria entre estas dos implementaciones. Todo esto se debe al hecho de que para reducir la creación repetida de objetos de cadena, la JVM mantiene una memoria especial. Esta memoria se denomina grupo constante de cadenas o grupo literal de cadenas.
Principio de funcionamiento
Cuando se crea un objeto de cadena en forma de literal en el código, la JVM primero verificará el literal. Si hay una referencia a un objeto de cadena con el mismo contenido en el grupo de constantes de cadena, se devolverá la referencia; Se creará una nueva cadena. Se crea el objeto, esta referencia se coloca en el grupo de constantes de cadena y se devuelve la referencia.
dar un ejemplo
Forma de creación literal
Copie el código de código de la siguiente manera:
Cadena str1 = "droide";
La JVM detecta este literal. Aquí pensamos que no hay ningún objeto cuyo contenido sea droide. La JVM no puede encontrar la existencia de un objeto de cadena con el contenido de droid a través del grupo de constantes de cadena, luego creará el objeto de cadena, luego colocará la referencia del objeto recién creado en el grupo de constantes de cadena y devolverá la referencia al variable cadena1.
Si hay un fragmento de código como este a continuación
Copie el código de código de la siguiente manera:
Cadena str2 = "droide";
De manera similar, la JVM aún necesita detectar este literal. La JVM busca en el grupo de constantes de cadena y descubre que el objeto de cadena con el contenido de "droid" existe, por lo que devuelve la referencia del objeto de cadena existente a la variable str2. Tenga en cuenta que aquí no se recrea un nuevo objeto de cadena.
Para verificar si str1 y str2 apuntan al mismo objeto, podemos usar este código
Copie el código de código de la siguiente manera:
System.out.println(str1 == str2);
El resultado es cierto.
Crear usando nuevo
Copie el código de código de la siguiente manera:
String str3 = new String("droide");
Cuando usamos new para construir un objeto de cadena, se creará un nuevo objeto de cadena independientemente de si hay una referencia a un objeto con el mismo contenido en el grupo de constantes de cadena. Entonces usamos el siguiente código para probarlo,
Copie el código de código de la siguiente manera:
String str3 = new String("droide");
System.out.println(str1 == str3);
El resultado es falso como pensábamos, lo que indica que las dos variables apuntan a objetos diferentes.
interno
Para el objeto de cadena creado usando new arriba, si desea agregar la referencia de este objeto al grupo constante de cadena, puede usar el método interno.
Después de llamar al interno, primero verifique si hay una referencia al objeto en el grupo de constantes de cadena. Si existe, devuelva la referencia a la variable. De lo contrario, agregue la referencia y devuélvala a la variable.
Copie el código de código de la siguiente manera:
Cadena str4 = str3.intern();
System.out.println(str4 == str1);
El resultado de salida es verdadero.
Preguntas difíciles
¿Requisito previo?
El requisito previo para la implementación del grupo constante de cadenas es que el objeto String en Java sea inmutable, lo que puede garantizar de forma segura que varias variables compartan el mismo objeto. Si el objeto String en Java es mutable y una operación de referencia cambia el valor del objeto, otras variables también se verán afectadas. Obviamente esto no es razonable.
referencia u objeto
El problema más común es si las referencias u objetos se almacenan en el grupo constante de cadenas. El grupo de constantes de cadena almacena referencias de objetos, no objetos. En Java, los objetos se crean en la memoria del montón.
Verificación de actualización, muchos comentarios recibidos también discuten este tema, simplemente lo verifiqué. Entorno de verificación:
Copie el código de código de la siguiente manera:
22:18:54-androidyue~/Videos$ cat /etc/os-release
NOMBRE=Fedora
VERSIÓN="17 (Milagro fornido)"
ID=fedora
VERSIÓN_ID=17
PRETTY_NAME="Fedora 17 (Milagro fornido)"
ANSI_COLOR="0;34"
CPE_NAME="cpe:/o:fedoraproject:fedora:17"
22:19:04-androidyue~/Videos$ java -versión
versión de Java "1.7.0_25"
Entorno de ejecución OpenJDK (fedora-2.3.12.1.fc17-x86_64)
VM de servidor OpenJDK de 64 bits (compilación 23.7-b01, modo mixto)
Idea de verificación: el siguiente programa Java lee un archivo de video con un tamaño de 82 M y realiza operaciones internas en forma de cadenas.
Copie el código de código de la siguiente manera:
22:01:17-androidyue~/Videos$ ll -lh | grepWhy_to_learn.mp4
-rw-rw-r--. 1 androidyue androidyue 82M 20 de octubre de 2013Why_to_learn.mp4
Código de verificación
Copie el código de código de la siguiente manera:
importar java.io.BufferedReader;
importar java.io.FileNotFoundException;
importar java.io.FileReader;
importar java.io.IOException;
prueba de clase pública principal {
contenido de archivo de cadena estática privada;
público estático vacío principal (String [] argumentos) {
contenido de archivo = readFileToString(args[0]);
si (nulo! = contenido de archivo) {
contenido de archivo = contenido de archivo.intern();
System.out.println("No nulo");
}
}
cadena estática privada readFileToString (archivo de cadena) {
Lector BufferedReader = nulo;
intentar {
lector = nuevo BufferedReader(nuevo FileReader(archivo));
Mejora de StringBuffer = nuevo StringBuffer();
Línea de cuerda;
mientras ((línea = lector.readLine()) != nulo) {
buff.append(línea);
}
devolver buff.toString();
} captura (FileNotFoundException e) {
e.printStackTrace();
} captura (IOException e) {
e.printStackTrace();
} finalmente {
si (nulo! = lector) {
intentar {
lector.close();
} captura (IOException e) {
e.printStackTrace();
}
}
}
devolver nulo;
}
}
Dado que el grupo constante de cadenas existe en la generación permanente en la memoria del montón, es aplicable antes de Java8. Verificamos esto estableciendo la generación permanente en un valor muy pequeño. Si el objeto de cadena existe en el grupo de constantes de cadena, inevitablemente se generará el error de espacio permgen java.lang.OutOfMemoryError.
Copie el código de código de la siguiente manera:
java -XX:PermSize=6m TestMain ~/Videos/why_to_learn.mp4
La ejecución del programa de prueba no arrojó OOM. De hecho, esto no puede probar muy bien si se almacenan objetos o referencias.
Pero esto al menos prueba que el objeto de contenido real char[] de la cadena no se almacena en el grupo constante de cadenas. En este caso, en realidad no es tan importante si el grupo de constantes de cadena almacena objetos de cadena o referencias a objetos de cadena. Pero personalmente prefiero guardarlo como referencia.
Ventajas y desventajas
La ventaja del grupo constante de cadenas es reducir la creación de cadenas con el mismo contenido y ahorrar espacio en la memoria.
Si insistimos en hablar de desventajas es que se sacrifica tiempo de cálculo de la CPU a cambio de espacio. El tiempo de cálculo de la CPU se utiliza principalmente para encontrar si hay una referencia a un objeto con el mismo contenido en el grupo de constantes de cadena. Sin embargo, su implementación interna es HashTable, por lo que el costo de cálculo es bajo.
¿Reciclaje de GC?
Debido a que el grupo de constantes de cadena contiene referencias a objetos de cadena compartidos, ¿significa esto que estos objetos no se pueden reciclar?
En primer lugar, los objetos compartidos en la pregunta son generalmente relativamente pequeños. Hasta donde yo sé, este problema existía en versiones anteriores, pero con la introducción de referencias débiles, este problema debería desaparecer ahora.
Respecto a este tema, puedes conocer más en este artículo interno Strings: Glosario de Java
uso interno?
El requisito previo para utilizar intern es que sepas que realmente necesitas usarlo. Por ejemplo, tenemos millones de registros aquí y un determinado valor en el registro es California, EE. UU. muchas veces. No queremos crear millones de dichos objetos de cadena. Podemos usar intern para mantener solo una copia en la memoria. Poder. Para obtener una comprensión más profunda de pasante, consulte Análisis en profundidad de String#intern.
¿Siempre hay excepciones?
¿Sabe que el siguiente código creará varios objetos de cadena y guardará varias referencias en el grupo de constantes de cadena?
Copie el código de código de la siguiente manera:
Prueba de cadena = "a" + "b" + "c";
La respuesta es que solo se crea un objeto y solo se guarda una referencia en el grupo constante. Podemos averiguarlo usando javap para descompilarlo y echarle un vistazo.
Copie el código de código de la siguiente manera:
17:02 $ javap -c TestInternedPoolGC
Compilado de "TestInternedPoolGC.java"
la clase pública TestInternedPoolGC extiende java.lang.Object{
público TestInternedPoolGC();
Código:
0: carga_0
1: invokespecial #1; //Método java/lang/Object."<init>":()V
4: regreso
public static void main(java.lang.String[]) lanza java.lang.Exception;
Código:
0: ldc #2; //cadena abc
2: astore_1
3: regreso
¿Viste que durante la compilación, estos tres literales se combinaron en uno solo? En realidad, esta es una optimización que evita la creación de objetos de cadena redundantes y no causa problemas de empalme de cadenas. Con respecto al empalme de cadenas, puede ver los detalles de Java: Empalme de cadenas.