tipos separar por lenguaje humano espacio elementos ejemplos ejemplo como caracteres caracter blanco java string performance jvm pool

separar - Mecanismo subyacente de la agrupación de cadenas en Java?



substring java (7)

Tenía curiosidad sobre por qué las cadenas se pueden crear sin una llamada a la new String() , ya que la API menciona que es un Object de la class java.lang.String

Entonces, ¿cómo podemos usar String s="hi" lugar de String s=new String("hi") ?

Esta publicación aclaró el uso del operador == y la ausencia de new y dice que esto se debe a que los literales String están internados o tomados de un grupo literal por la JVM , por lo tanto, las Strings son inmutables.

Al ver una declaración como

String s="hi"

por primera vez, ¿qué pasa realmente?

  1. ¿La JVM reemplaza como este String s=new String("hi") , en el que se crea un objeto y se agrega "hi" al grupo literal String y las llamadas subsiguientes como String s1="hi" se toman del ¿piscina?

  2. ¿Es así como funciona el mecanismo subyacente? Si es así, entonces es

    String s=new String("Test"); String s1="Test";

    lo mismo que

    String s="Test"; String s1="Test";

    en términos de utilización y eficiencia de la memoria?

  3. Además, ¿hay alguna manera de poder acceder al conjunto de cadenas para comprobar cuántos literales de String están presentes en él, cuánto espacio está ocupado, etc.?


  1. String s="hi" por primera vez, ¿qué pasa realmente?

¿La JVM lo reemplaza como este String s=new String("hi") , en el que se crea un objeto y se agrega "hi" al grupo literal String y las llamadas subsiguientes como String s1 = "hi" se toman del piscina?

No. Lo que realmente sucede es que los literales de cadena se resuelven durante el tiempo de compilación y se internan (se agregan al conjunto de constantes de cadena) tan pronto como la clase se carga / inicializa o se va relajando . Por lo tanto, están disponibles para las clases dentro de la JVM. Tenga en cuenta que, incluso si tiene un String con el valor "hi" en el conjunto de constantes Strings, el new String("hi") creará otro String en el montón y devolverá su referencia.

  1. es

String s=new String("Test"); String s1="Test";

lo mismo que

String s="Test"; String s1="Test";

en términos de utilización y eficiencia de la memoria?

No, en el primer caso se crean 2 cadenas de "prueba". Se agregará uno al conjunto de constantes de String (suponiendo que no esté presente allí) y otro en el montón. El segundo puede ser GCed. En el segundo caso, solo un literal String está presente en el conjunto de constantes String y hay 2 referencias a él ( s y s1 ).

  1. Además, si hay alguna forma de acceder al grupo de cadenas para comprobar cuántos literales de cadena están presentes en él, espacio ocupado, etc. del programa o de cualquier herramienta de supervisión.

No creo que podamos ver el contenido del conjunto de constantes String. Simplemente podemos asumir y confirmar el comportamiento en función de nuestras suposiciones.


  1. Una especie de, pero no exactamente.
    Las constantes de cadena se crean y se internan durante la resolución constante de la agrupación . Esto ocurre con la primera ejecución del bytecode de LDC que carga un literal de cadena. Después de la primera ejecución, la JVM reemplaza la etiqueta JVM_CONSTANT_UnresolvedString constant pool con la etiqueta JVM_CONSTANT_String para que la próxima vez LDC tome una cadena existente en lugar de crear una nueva.

  2. No. El primer uso de "Test" creará un nuevo objeto de cadena. Entonces una new String("Test") creará el segundo objeto.

  3. Sí, usando el agente de servicio de HotSpot . Aquí hay un ejemplo .


Creo que el mecanismo subyacente para crear una cadena es un StringBuilder que ensambla el objeto String al final. Al menos, estoy seguro de que si tiene una cadena que desea cambiar, por ejemplo:

String str = "my String"; // and then do System.out.println(str + "new content");

Entonces, lo que hace es crear un StrigBuilder a partir del antiguo objeto y lo reemplaza con uno nuevo que se construye desde el constructor. Esta es la razón por la que es más eficiente con la memoria utilizar StringBuilder en lugar de una cadena normal a la que solo anexaría cosas.

Hay una forma de acceder al grupo de cadenas de caracteres ya creado que está utilizando el método String.intern (). Le dice a Java que use el mismo espacio de memoria para cadenas que son iguales y le da una referencia a ese lugar en la memoria. Esto también le permite usar el operador == para comparar cadenas y es más eficiente con la memoria.


El compilador de Java tiene soporte especial para literales de cadenas. Supongamos que no es así, entonces sería muy engorroso crear cadenas en su código fuente, tendría que escribir algo como:

// Suppose that we would not have string literals like "hi" String s = new String(new char[]{ ''h'', ''i'' });

Para responder tu pregunta:

  1. Más o menos, y si realmente quieres saber los detalles, tendrías que estudiar el código fuente de la JVM, que puedes encontrar en OpenJDK , pero ten en cuenta que es enorme y complicado.

  2. No, esos dos no son equivalentes. En el primer caso, está creando explícitamente un nuevo objeto String :

    String s=new String("Test");

    que contendrá una copia del objeto String representado por el literal "Test" . Tenga en cuenta que nunca es una buena idea escribir un new String("some literal") en Java: las cadenas son inmutables, y nunca es necesario hacer una copia de un literal de cadena.

  3. No hay forma de que yo sepa de verificar lo que hay en el grupo de cadenas.


Eso no está estrechamente relacionado con el tema, pero cada vez que tenga dudas sobre qué hará el compilador de Java, puede usar el

javap -c CompiledClassName

para imprimir lo que realmente está pasando. (CompiledClassName del directorio donde compiledClassName.class es)

Para agregar a la respuesta de Jesper, hay más mecanismos en funcionamiento, como cuando concatenas un String de literales o variables finales, aún usará el grupo interno:

String s0 = "te" + "st"; String s1 = "test"; final String s2 = "te"; String s3 = s2 + "st"; System.out.println(s0==s1); //true System.out.println(s3==s1); //true

Pero cuando concatenas usando variables no finales, no usará el grupo:

String s0 = "te"; String s1 = s0 + "st"; String s2 = "test"; System.out.println(s1 == s2); //false


La siguiente es una ligera simplificación, por lo que no intente citar detalles exactos de ella, pero se aplican los principios generales.

Cada clase compilada de Java contiene un blob de datos que indica cuántas cadenas se declararon en ese archivo de clase, cuánto tiempo es cada una y los caracteres que pertenecen a todas ellas. Cuando se carga la clase, el cargador de clases creará un String[] de tamaño adecuado para contener todas las cadenas definidas en esa clase; para cada cadena, generará un char[] de tamaño adecuado, leerá el número apropiado de caracteres del archivo de clase en el char[] , creará un String encapsulando esos caracteres y almacenará la referencia en el String[] la clase.

Al compilar alguna clase (por ejemplo, Foo ), el compilador sabe qué cadena de literales encuentra primero, segundo, tercero, quinto, etc. Si el código dice myString = "George"; y George fue el sexto verso de cadena, que aparecerá en el código como una instrucción "cadena de carga literal # 6"; el compilador just-at-time, cuando está generando código para esa instrucción, generará una instrucción para buscar la sexta referencia de cadena asociada con esa clase.


String pool como grupo de cadena almacenado en heap for exp:

String s="Test"; String s1="Test";

ambos se almacenan en el montón y se refiere a una sola "Prueba" por lo tanto s1 = s, mientras

String s=new String("Test");

es un objeto que también se almacena en el montón, pero diferentes formas s1 = s se refieren aquí