java string string-concatenation string-pool string-building

java - ¿Cuántos objetos de cadena se crearían al concatenar cadenas múltiples?



string string-concatenation (7)

Me preguntaron en una entrevista sobre la cantidad de objetos que se crearán en el problema dado:

String str1 = "First"; String str2 = "Second"; String str3 = "Third"; String str4 = str1 + str2 + str3;

Respondí que habría 6 objetos creados en el grupo de cadenas.

3 sería para cada una de las tres variables.
1 sería para str1 + str2 (digamos str ).
1 sería para str2 + str3 .
1 sería para str + str3 ( str = str1 + str2 ).

¿Es correcta la respuesta que di? Si no, ¿cuál es la respuesta correcta?


Con la información dada, la pregunta no puede ser respondida definitivamente. Como se establece en el JLS, §15.18.1 :

... Para aumentar el rendimiento de la concatenación de cadenas repetida, un compilador de Java puede usar la clase StringBuffer o una técnica similar para reducir el número de objetos de cadena intermedios que se crean mediante la evaluación de una expresión.

Esto significa que la respuesta depende al menos del compilador concreto de Java utilizado.

Creo que lo mejor que podemos hacer es dar un intervalo como respuesta:

  • un compilador inteligente puede inferir que str1 a str3 nunca se usan y plegar la concatenación durante la compilación, de modo que solo se crea un String -object (el referenciado por str4 )
  • El número sensible máximo de String creadas debe ser 5: una para str1 a str3 , una para tmp = str1 + str2 y otra para str4 = tmp + str3 .

Entonces ... mi respuesta sería "algo entre uno y cinco objetos de String ". En cuanto a la cantidad total de objetos creados solo para esta operación ... No lo sé. Esto también puede depender de cómo exactamente, por ejemplo, se implementa StringBuffer .

Como comentario: me pregunto cuál es la razón detrás de hacer tales preguntas. Normalmente, uno no necesita preocuparse por esos detalles.


Cualquier respuesta a su pregunta dependerá de la implementación de JVM y la versión de Java que se esté utilizando actualmente. Creo que es una pregunta irrazonable hacer en una entrevista.

Java 8

En mi máquina, con Java 1.8.0_201, su fragmento da como resultado este código de bytes

L0 LINENUMBER 13 L0 LDC "First" ASTORE 1 L1 LINENUMBER 14 L1 LDC "Second" ASTORE 2 L2 LINENUMBER 15 L2 LDC "Third" ASTORE 3 L3 LINENUMBER 16 L3 NEW java/lang/StringBuilder DUP INVOKESPECIAL java/lang/StringBuilder.<init> ()V ALOAD 1 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; ALOAD 2 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; ALOAD 3 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; ASTORE 4

lo que demuestra que se están creando 5 objetos (3 literales de String *, 1 StringBuilder , 1 instancia de String producida dinámicamente por StringBuilder#toString ).

Java 12

En mi máquina, con Java 12.0.2, el código de bytes es

// identical to the bytecode above L3 LINENUMBER 16 L3 ALOAD 1 ALOAD 2 ALOAD 3 INVOKEDYNAMIC makeConcatWithConstants(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; [ // handle kind 0x6 : INVOKESTATIC java/lang/invoke/StringConcatFactory.makeConcatWithConstants(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; // arguments: "/u0001/u0001/u0001" ] ASTORE 4

que magically cambia "la respuesta correcta" a 4 objetos ya que no hay ningún StringBuilder intermedio involucrado.

* Profundicemos un poco más.

12.5 Creación de nuevas instancias de clase

Una nueva instancia de clase puede crearse implícitamente en las siguientes situaciones:

  • La carga de una clase o interfaz que contiene un literal de cadena ( §3.10.5 ) puede crear un nuevo objeto de cadena para representar el literal. (Esto no ocurrirá si una cadena que denota la misma secuencia de puntos de código Unicode ha sido internada previamente).

En otras palabras, cuando inicia una aplicación, ya hay objetos en el conjunto de cadenas. Apenas sabe qué son y de dónde provienen (a menos que escanee todas las clases cargadas para todos los literales que contienen).

La clase java.lang.String se cargará indudablemente como una clase JVM esencial, lo que significa que todos sus literales se crearán y se colocarán en el grupo.

Tomemos un fragmento seleccionado al azar del código fuente de String , seleccionemos un par de literales, coloquemos un punto de interrupción al comienzo de nuestro programa y examinemos si el grupo contiene estos literales.

public final class String implements java.io.Serializable, Comparable<String>, CharSequence, Constable, ConstantDesc { ... public String repeat(int count) { // ... if (Integer.MAX_VALUE / count < len) { throw new OutOfMemoryError("Repeating " + len + " bytes String " + count + " times will produce a String exceeding maximum size."); } } ... }

Están allí de hecho.

Como hallazgo interesante, el filtrado de esta IDEA tiene un efecto secundario: las subcadenas que estaba buscando también se han agregado al grupo. El tamaño del grupo aumentó en uno (se agregó "bytes String" ) después de aplicar this.contains("bytes String") .

¿Dónde nos deja esto?

No tenemos idea de si "First" fue creado e internado antes de llamar a String str1 = "First"; , por lo que no podemos afirmar con firmeza que la línea crea una nueva instancia.


Debería ser 5:

  • tres para los tres literales (asignados a str1 , str3 y str3 )

  • uno para str1 + str2

  • uno para (result from the previous operation) + str3 (asignado a str4 )


Java 8 probablemente creará 5 objetos:

  • 3 para los 3 literales
  • 1 StringBuilder
  • 1 para la String concatenada

Sin embargo, con Java 9 las cosas cambiaron y String concatenación de String ya no usa StringBuilder .


La operación de concatenación no crea esos muchos objetos de cadena. Crea un StringBuilder y luego agrega las cadenas. Entonces puede haber 5 objetos, 3 (variables) + 1 (sb) + 1 (cadena concatenada).


Se crearán 4 objetos de cadena en el grupo de cadenas constantes. 3 para literales y 1 con concatenación.

si usamos

String s1 = new String("one")

creará dos objetos, uno en grupo constante y otro en memoria de almacenamiento dinámico.

si definimos:

String s1 = "one"; String s2 = new String("one");

creará dos objetos, uno en grupo constante y otro en memoria de almacenamiento dinámico.


Una implementación de Java conforme puede concatenar las cadenas de varias maneras, en tiempo de ejecución o en tiempo de compilación, necesitando cualquier cantidad de objetos de tiempo de ejecución, incluidos los objetos cero si detecta que el resultado no es necesario en tiempo de ejecución.