Consideremos una pregunta sobre la cadena en Java: la diferencia entre "ABC" + '/' y "ABC" + "/". A través de este ejemplo, podemos practicar el uso de Javap en herramientas JDK. La pregunta original es la siguiente:
¿Cuál es la diferencia entre tratar las bases/como caracteres o cuerdas?
Uno se usa como el tipo de datos básico Char, y el otro es la cadena de objeto. ¿Cuál es la diferencia específica?
¿Será más eficiente tratarlo como un personaje?
Cadena str = "ABC" + '/';
y
Cadena str = "ABC" + "/";
1. Optimización del compilador
En primer lugar, debe saber que las dos oraciones anteriores tienen el mismo efecto, porque el compilador optimizará las dos oraciones anteriores a las siguientes:
Cadena str = "abc/";
Podemos probar esto a través de Javap. Para Javap, podemos referirnos a "5 herramientas JDK que todo desarrollador de Java debe saber". Primero creamos una clase: StringOne y completamos el siguiente código en el método principal:
StringOne.javastring str1 = "ABC" + '/'; String str2 = "ABC" + "/" ;System.out.println(str1 == Str2);
Compilar y ejecutar, el resultado de salida es verdadero. A continuación, se inicia nuestro Javap, ingrese el siguiente comando en la línea de comando:
javap -v -l stringone.class> stringone.s
Luego verifique el archivo StringOne.s generado. Encontrarás que hay varias líneas en
StringOne.s #2 = String #20 // ABC /...# 20 = UTF8 ABC/... 0: LDC #2 // String ABC/2: Store_13: LDC #2 // String ABC/5: Store_2
Explicación: STR1 y STR2 se refieren a la cadena "ABC/".
2. Use Javap para analizar las diferencias
Ahora cambiemos la pregunta. ¿Cuál es la diferencia entre los métodos StringAddRing y StringAddchar en el siguiente código?
StringTwopublic static string stringAddString (string str1, string str2) {return str1 + str2;} public static string string StringDDar (string str, char ch) {return str + ch;}Esta vez, Javap se usa para la descompilación, y algunos de los contenidos del archivo generado son los siguientes
Stringtwo.spublic java.lang.string stringaddString (java.lang.string, java.lang.string); descriptor: (ljava/lang/string; ljava/lang/string;) ljava/lang/string; FLAGS: ACC_Public Code: stack = 2, locals = 3, args_size = 3 0: nuevo #2 // class java/lang/stringBuilder 3: dup 4: invokespecial #3 // método java/lang/stringbuilder. "<init>" :() v 7: Aload_1 8: Invokevirtual #4 // Method Java/Langa/Langa/Stringb. append: (ljava/lang/string;) ljava/lang/stringBuilder; 11: Aload_2 12: InvokeVirtual #4 // Método Java/Lang/StringBuilder. append: (ljava/lang/string;) ljava/lang/stringBuilder; 15: InvokeVirtual #5 // Método Java/Lang/StringBuilder. toString :() ljava/lang/string; 18: AreturnPublic java.lang.string stringaddchar (java.lang.string, char); descriptor: (ljava/lang/string; c) ljava/lang/string; FLAGS: ACC_Public Code: stack = 2, locals = 3, args_size = 3 0: nuevo #2 // class java/lang/stringBuilder 3: dup 4: invokespecial #3 // método java/lang/stringBuilder. "<init>" :() v 7: Aload_1 8: Invokevirtual #4 // Method java/lang/stringBuilder.append: (ljava/lang/string;) ljava/lang/stringBuilder; 11: ILOAD_2 12: InvokeVirtual #6 // método java/lang/stringBuilder.append: (c) ljava/lang/stringBuilder; 15: InvokeVirtual #5 // método java/lang/stringBuilder.ToString :() ljava/lang/string; 18: Areturn
Ahora, podemos ver claramente el proceso de ejecutar estos dos métodos:
StringAddRing
El procedimiento de StringAddchar es el mismo que StringAddString, excepto que cuando el método de agregado se llama la segunda vez, el parámetro de StringAddString es de tipo de cadena, mientras que el parámetro de StringAddchar es de tipo Char.
3. Método de append (char) y método append (string) de la clase StringBuilder
Aquí, solo necesitamos verificar el código fuente directamente (el mío es el código fuente que viene con JDK1.8.0_60). Tenga en cuenta que aunque el documento muestra que StringBuilder hereda del objeto, desde el código fuente, se hereda de la clase abstracta AbstractStringBuilder. Y el método Append es implementado por AbstractStringBuilder.
AbstractStringBuilder.java
Public AbstractStringBuilder append (char c) {EnsurecapacityInternal (recuento + 1); // Asegúrese de que la matriz pueda acomodar el valor de conteo+1 caracteres [count ++] = c; devolver esto;} public AbstractStringBuilder append (String Str) {if (str == null) return appendNull (); int len = str.length (); EnsurecapacityInternal (recuento + len); str.getChars (0, len, valor, recuento); // Copiar la matriz de caracteres en la cadena en la matriz de caracteres de este conteo de objeto += len; devolver esto;}El resto ya no se publicará. String.getChars (int, int, char [], int) en última instancia depende de la arrayCopy void nativa estática pública (objeto, int, objeto, int, int). En otras palabras, se puede escribir en lenguaje C, y la eficiencia debería ser mejor al copiar grandes matrices que los programas escritos en Java. Entonces, ahora déjame decirte lo que entiendo:
En términos de memoria directa, dado que la cadena contiene matrices de char, la matriz debe tener campos de longitud. Al mismo tiempo, la clase de cadena también tiene una propiedad int hash, y el objeto en sí ocupará memoria adicional para almacenar otra información, por lo que la cadena ocupará más memoria. Sin embargo, si la cadena es muy larga, estos gastos generales de memoria pueden ser casi ignorados; Y si la cadena es (muy) corta, entonces hay muchas referencias compartidas para compartir estos gastos generales de memoria, por lo que la sobrecarga de memoria excesiva aún se puede ignorar.
Desde la pila de llamadas, ya que la cadena solo tiene una o dos llamadas de función más que Char aquí, si no se considera la sobrecarga de llamadas de función (incluido el tiempo y el espacio), debería ser similar; Si se considera la sobrecarga de llamadas de función, "ABC" + '/' debería ser mejor; Pero cuando varios personajes deben estar conectados (creo que esta situación debería ser más común, ¿verdad?), Dado que el uso de Char requiere muchos bucles para completar la conexión, el número de funciones llamadas solo se llamará más que usar cadena. Al mismo tiempo, la copia no será más rápida que la cadena copiando directamente una matriz. Entonces, en este momento, se convierte en "ABC" + "/" con un rendimiento mayor.
Ahora siento que esta pregunta es: ¿es más eficiente usar llamadas del sistema al leer y escribir archivos, o es más eficiente usar la biblioteca IO en la biblioteca de funciones estándar? Personalmente, siento que, aunque la biblioteca de IO estándar tiene que llamar al final, y se generarán algunas variables temporales y pilas de llamadas más profundas, debido a los mecanismos de amortiguación de la biblioteca IO, el rendimiento de la biblioteca IO será mayor, y el rendimiento en tiempo real de las llamadas del sistema será mejor. Del mismo modo, aunque la clase de cadena tendrá más campos y una pila de funciones más profunda, el rendimiento debería ser mejor debido a la caché y una copia más directa.
Nuevas preguntas
A juzgar por el código de descompilación Javap anterior, cuando se suman las dos cadenas, se convertirán en cadenas de anexos en StringBuilder. Entonces, en teoría, ¿cuál del siguiente código es más eficiente?
Cadena str1 = "ABC" + "123"; // 1StringBuilder StringBuilder = new StringBuilder (); // 2StringBuilder.Append ("ABC"); StringBuilder.Append ("123"); String str2 = StringBuilder.ToString ();¡Que se deje esta pregunta para que todos piensen!
Lo anterior es todo el contenido de este artículo, lo que le ayuda a distinguir mejor String+String y String+Char en Java. Espero que sea útil para el aprendizaje de todos.