Estaba ocupado con la implementación lógica del proyecto de lunes a viernes. Tuve algo de tiempo el sábado, así que saqué una versión gruesa de pensamiento en Java de la estantería y leí el empalme de objetos de cadena. Consulte este libro como una traducción, agregue lo que piense y escriba este artículo para grabarlo.
Objeto de cadena inmutable
En Java, los objetos de cadena son inmutables (inmutables). En el código, puede crear múltiples alias para un objeto de cadena. Pero las referencias de estos alias son las mismas.
Por ejemplo, S1 y S2 son alias para objetos "droidyue.com", y los alias se almacenan en referencias al objeto real. Entonces S1 = S2
String S1 = "droidyue.com"; String S2 = S1; System.out.println ("S1 y S2 tiene la misma referencia =" + (S1 == S2));El único operador sobrecargado en Java
En Java, el único operador sobrecargado está relacionado con el empalme de cadena. +,+=. Además de eso, los diseñadores de Java no permiten sobrecargar a otros operadores.
Análisis de empalme
¿Hay realmente un costo de rendimiento?
Después de comprender los dos puntos anteriores, puede tener tales pensamientos. Dado que el objeto Sting es inmutable, el empalme de las cadenas múltiples (tres o más) inevitablemente producirá objetos de cadena intermedios innecesarios.
String UserName = "Andy"; String Age = "24"; String Job = "Developer"; String Info = UserName + Age + Job;
Para obtener la información anterior, el nombre de usuario y la edad se empalmarán para generar un objeto de cadena temporal T1, con el contenido de Andy24, y luego T1 y los trabajos se empalmarán para generar el objeto de información que necesitamos al final. Entre ellos, se genera un T1 intermedio, y después de que se cree T1, no se reciclará automáticamente, lo que inevitablemente ocupará una cierta cantidad de espacio. Si se trata de un empalme de una cadena de lote (suponiendo cientos, más común en la llamada de tostración al objeto), entonces el costo será mayor y el rendimiento será mucho más bajo.
Procesamiento de optimización del compilador
¿Existe realmente el costo de rendimiento anterior? El empalme de cadenas es tan común, ¿no hay una optimización de procesamiento especial? La respuesta es que esta optimización se realiza cuando el compilador compila .java a bytecode.
Si un programa Java quiere ejecutarse, tomará dos períodos, compilará tiempo y tiempo de ejecución. En el momento de la compilación, el compilador Java (compilador) convierte el archivo java en bytecode. En tiempo de ejecución, la máquina virtual Java (JVM) ejecuta el tiempo de compilación generado por el código de bytecode. A través de estos dos períodos, Java ha logrado la llamada compilación y corriendo en todas partes.
Experimentemos con qué optimizaciones se hicieron durante el período de compilación, y creamos un código que puede tener costos de rendimiento.
Concatenación de clase pública {public static void main (String [] args) {String UserName = "Andy"; String Age = "24"; String Job = "Developer"; Info de cadena = nombre de usuario + edad + trabajo; System.out.println (info); }}Compilar concatenation.java. Obtenga concatenation.class
Concatenación de Javac.java
Luego usamos Javap para descompilar el archivo de concatenation.class compilado. Javap -C Concatenation. Si no se encuentra el comando Javap, considere agregar el directorio donde el Javap se encuentra a la variable de entorno o usando la ruta completa de Javap.
17: 22: 04 -androidyue ~/workspace_adt/strings/src $ javap -c concatenation compilado de "concatenation.java" concatenación de clase pública {concatenación pública (); Código: 0: Aload_0 1: Invokespecial #1 // Method java/lang/object. "<Init>" :() v 4: return public static void main (java.lang.string []); Código: 0: LDC #2 // String Andy 2: Store_1 3: LDC #3 // String 24 5: Store_2 6: LDC #4 // String Developer 8: Store_3 9: New #5 // class java/lang/stringBuilder 12: dup 13: Invokespecial #6 // método java/lang/stringbuilder. "<<th inicio>") V 16) InvokeVirtual #7 // método java/lang/stringBuilder.append: (ljava/lang/string;) ljava/lang/stringBuilder; 20: Aload_2 21: InvokeVirtual #7 // método java/lang/stringBuilder.append: (ljava/lang/string;) ljava/lang/stringBuilder; 24: Aload_3 25: InvokeVirtual #7 // método java/lang/stringBuilder.append: (ljava/lang/string;) ljava/lang/stringBuilder; 28: InvokeVirtual #8 // método java/lang/stringBuilder.ToString :() ljava/lang/string; 31: Store 4 33: Getstatic #9 // Field java/lang/system.out: ljava/io/printstream; 36: Aload 4 38: InvokeVirtual #10 // Método Java/io/printstream.println: (ljava/lang/string;) v 41: return}Entre ellos, LDC, Store, etc. se encuentran las instrucciones de Bytecode Java, similares a las instrucciones de ensamblaje. Los siguientes comentarios usan contenido relacionado con Java para explicación. Podemos ver que hay muchos StringBuilders en él, pero los llamamos sin visualización en el código Java. Esta es la optimización realizada por el compilador Java. Cuando el compilador Java encuentra el empalme de cadena, creará un objeto StringBuilder. El empalme detrás de esto en realidad está llamando al método de adición del objeto StringBuilder. De esta manera, no habrá problemas que nos preocupe.
¿Optimización del compilador solo?
Dado que el compilador nos ha ayudado a optimizar, ¿es suficiente para confiar únicamente en la optimización del compilador? Por supuesto que no.
Veamos un código que no ha sido optimizado para un bajo rendimiento
public void implicituseStringBuilder (String [] valores) {String result = ""; for (int i = 0; i <valores.length; i ++) {result += valores [i]; } System.out.println (resultado);}Compilar con Javac y ver con Javap
11: new #5 // class java/lang/StringBuilder 14: dup 15: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V 18: aload_2 19: invokevirtual #7 // Method 31: store_2 32: iinc 3, 1 35: goto 5 38: getstatic #9 // Field java/lang/system.out: ljava/io/printstream; 41: Aload_2 42: InvokeVirtual #10 // Método java/io/printstream.println: (ljava/lang/string;) v 45: return
Entre ellos 8: IF_ICMPGE 38 y 35: GOTO 5 Forma un bucle. 8: IF_ICMPGE 38 significa que si la comparación entera de la pila de operando JVM es mayor o igual que (el resultado opuesto de i <valores.length) es verdadera, salte a la línea 38 (System.out). 35: GoTo 5 significa saltar directamente a la línea 5.
Pero aquí hay algo muy importante que la creación de objetos StringBuilder ocurre entre los bucles, lo que significa que cuántas veces los bucles crearán objetos StringBuilder, lo que obviamente no es bueno. Código desnudo de bajo nivel.
Optimice ligeramente para mejorar instantáneamente la calidad.
public void ExplicitUseCringBuilder (String [] valores) {stringBuilder result = new StringBuilder (); for (int i = 0; i <value.length; i ++) {result.append (valores [i]); }}Información compilada correspondiente
public void ExplicitUseCringBuider (java.lang.string []); Código: 0: Nuevo #5 // clase java/lang/stringBuilder 3: dup 4: invokespecial #6 // método java/lang/stringBuilder. "<Init>" :() v 7: Astore_2 8: Iconst_0 9: istore_3 10: Iiload_3 11: Aload_1 12: ArrayLength 13: if_icmpge 30 16: Aload_1 18: ILOAD_3 19: Aaload 20: InvokeVirtual #7 // método java/lang/stringBuilder.append: (ljava/lang/string;) ljava/lang/stringBuilder; 23: Pop 24: Iinc 3, 1 27: GoTo 10 30: Regreso
Como se puede ver desde arriba, 13: IF_ICMPGE 30 y 27: GOTO 10 Forma un bucle de bucle, mientras que 0: el nuevo #5 está fuera del bucle, por lo que StringBuilder no se crea varias veces.
En general, debemos tratar de evitar la creación implícita o explícita de StringBuilders en el cuerpo del bucle. Por lo tanto, aquellos que entienden cómo se compila el código y cómo se ejecuta internamente tienen niveles de código relativamente altos.
Si hay algún error en el artículo anterior, críquelos y corrijalos.
Lo anterior es ordenar la información sobre el empalme de las cuerdas Java, y continuaremos agregando información relevante en el futuro. ¡Gracias por su apoyo para este sitio web!