Creo que todos comprenden bien la diferencia entre String y StringBuffer, pero se estima que todavía hay muchos compañeros que no tienen claros los principios de funcionamiento de estas dos clases. Hoy revisaré este concepto para todos, y por. el camino Hay una nueva clase de operación de caracteres introducida en J2SE 5.0: StringBuilder. Entonces, ¿cuáles son las diferencias entre StringBuilder y StringBuffer y la clase String que conocimos por primera vez? ¿Cuál deberíamos utilizar en diferentes situaciones? Me gustaría compartir mis puntos de vista sobre estas categorías, y también espero que todos puedan dar sus opiniones. Todos han cometido errores, y mientras los corrigen, es una buena oportunidad para aprender.
En pocas palabras, la principal diferencia de rendimiento entre el tipo String y el tipo StringBuffer es en realidad que String es un objeto inmutable (¿Por qué? Pregúntele a los diseñadores de Java, ¿por qué String no es un tipo nativo?) Por lo tanto, cada vez que se cambia el tipo String De hecho, es equivalente a generar un nuevo objeto String y luego apuntar el puntero al nuevo objeto String. Por lo tanto, es mejor no utilizar String para cadenas que cambian con frecuencia. Porque cada vez que se genera un objeto, tendrá un impacto en el rendimiento del sistema. Especialmente cuando hay demasiados objetos sin referencia en la memoria, el GC de la JVM comenzará a funcionar y la velocidad definitivamente será bastante lenta. He aquí un ejemplo que no es muy apropiado:
Si este es el caso, una vez completado el bucle for, si el GC no ha borrado los objetos de la memoria, habrá más de 20.000 en la memoria, un número sorprendente, y si este es un sistema utilizado por muchos personas, entonces el número no es muy grande, por lo que todos deben tener cuidado al usarlo.
Si usa la clase StringBuffer, los resultados serán diferentes cada vez que el resultado será una operación en el objeto StringBuffer en sí, en lugar de generar un nuevo objeto y luego cambiar la referencia del objeto. Por lo tanto, en general recomendamos usar StringBuffer, especialmente cuando los objetos de cadena cambian con frecuencia. En algunos casos especiales, la JVM interpreta la concatenación de cadenas de objetos String como la concatenación de objetos StringBuffer, por lo que en estos casos la velocidad de los objetos String no será más lenta que la de los objetos StringBuffer, y especialmente los siguientes objetos de cadena son generado Entre ellos, la eficiencia de String es mucho más rápida que StringBuffer:
Se sorprenderá al descubrir que la velocidad de generación de objetos String S1 es simplemente demasiado rápida y, en este momento, StringBuffer no tiene ninguna ventaja en velocidad. De hecho, esto es un truco de la JVM. A los ojos de la JVM, esto.
De esto obtenemos la conclusión del primer paso: en la mayoría de los casos StringBuffer > String
¿Y cómo se compara StringBuilder con ellos? Permítanme presentarles brevemente primero. StringBuilder es una clase recién agregada en JDK5.0. La diferencia entre ella y StringBuffer es la siguiente (fuente: JavaWorld):
Java.lang.StringBuffer Secuencia de caracteres mutables segura para subprocesos. Un búfer de cadena similar a String, pero que no se puede modificar. Los buffers de cadenas pueden ser utilizados de forma segura por múltiples subprocesos. Estos métodos se pueden sincronizar cuando sea necesario, de modo que todas las operaciones en cualquier instancia particular parezcan ocurrir en un orden en serie consistente con el orden de las llamadas a métodos realizadas por cada subproceso involucrado.
Cada búfer de cadena tiene una capacidad determinada. Siempre que la longitud de la secuencia de caracteres contenida en el búfer de cadena no exceda esta capacidad, no es necesario asignar una nueva matriz de búfer interna. Esta capacidad aumenta automáticamente si el búfer interno se desborda. A partir de JDK 5.0, se ha agregado a esta clase una clase equivalente para uso de un solo subproceso, StringBuilder. La clase StringBuilder generalmente debe usarse con preferencia a esta clase porque admite las mismas operaciones pero es más rápida porque no realiza sincronización.
Pero no es seguro utilizar una instancia de StringBuilder con varios subprocesos. Si se requiere dicha sincronización, se recomienda utilizar StringBuffer.
Dicho esto, creo que todos pueden entender la diferencia entre ellos, así que hagamos una derivación general a continuación:
En la mayoría de los casos StringBuilder > StringBuffer
Por lo tanto, según el teorema transitivo de esta desigualdad: En la mayoría de los casos StringBuilder > StringBuffer > String
Ahora que tenemos esos resultados de derivación, hagamos una prueba para verificar:
El código de prueba es el siguiente:
/** Crea una nueva instancia de testssb */
final static int ttime = 10000;//Número de bucles de prueba
pruebas públicassb() {
}
prueba de anulación pública (cadena s) {
comienzo largo = System.currentTimeMillis();
para(int i=0;i<ttime;i++){
s += "añadir";
}
mucho tiempo = System.currentTimeMillis();
System.out.println("El tiempo utilizado por la operación del tipo "+s.getClass().getName()+" es: " + (sobre - comienzo) + " milisegundos ");
}
prueba de anulación pública (StringBuffer s) {
comienzo largo = System.currentTimeMillis();
para(int i=0;i<ttime;i++){
s.append("añadir");
}
mucho tiempo = System.currentTimeMillis();
System.out.println("El tiempo utilizado por la operación del tipo "+s.getClass().getName()+" es: " + (sobre - comienzo) + " milisegundos ");
}
prueba de anulación pública (StringBuilder s) {
comienzo largo = System.currentTimeMillis();
para(int i=0;i<ttime;i++){
s.append("añadir");
}
mucho tiempo = System.currentTimeMillis();
System.out.println("El tiempo utilizado por la operación del tipo "+s.getClass().getName()+" es: " + (sobre - comienzo) + " milisegundos ");
}
// Probar directamente la concatenación de cadenas en String
prueba de anulación pública2(){
Cadena s2 = "abadf";
comienzo largo = System.currentTimeMillis();
para(int i=0;i<ttime;i++){
Cadena s = s2 + s2 + s2;
}
mucho tiempo = System.currentTimeMillis();
System.out.println("El tiempo utilizado para operar el tipo de adición de referencia de objeto de cadena es: " + (sobre - comenzar) + " milisegundos ");
}
prueba de anulación pública3(){
comienzo largo = System.currentTimeMillis();
para(int i=0;i<ttime;i++){
Cadena s = "abadf" + "abadf" + "abadf";
}
mucho tiempo = System.currentTimeMillis();
System.out.println("El tiempo utilizado para agregar cadenas de operación es: "+ (sobre - comenzar) + "milisegundos");
}
principal vacío estático público (String [] argumentos) {
Cadena s1="abc";
StringBuffer sb1 = nuevo StringBuffer("abc");
StringBuilder sb2 = nuevo StringBuilder("abc");
pruebassb t = nuevas pruebassb();
t.prueba(s1);
t.prueba(sb1);
t.prueba(sb2);
t.prueba2();
t.test3();
}
}
Parece que todavía no puedes ver la diferencia entre StringBuffer y StringBuilder. Agrega ttime a 30000 veces y mira:
El tiempo utilizado para operar el tipo java.lang.String es: 53444 milisegundos El tiempo utilizado para operar el tipo java.lang.StringBuffer es: 15 milisegundos El tiempo utilizado para operar el tipo java.lang.StringBuilder es: 15 milisegundos El tiempo utilizado para operar el tipo de adición de referencia de objeto de cadena Tiempo necesario: 31 milisegundos La adición de cadenas tomó tiempo: 0 milisegundos
Todavía no hay mucha diferencia en el rendimiento entre StringBuffer y StringBuilder. Aumentémoslo a 100000 y echemos un vistazo. No agregaremos pruebas para el tipo String aquí, porque probar una cantidad tan grande de datos para el tipo String. muy lento...
El tiempo necesario para operar el tipo java.lang.StringBuffer es: 31 milisegundos El tiempo necesario para operar el tipo java.lang.StringBuilder es: 16 milisegundos
Puede ver la diferencia, pero muchos de los resultados de las pruebas muestran que StringBuffer es más rápido que StringBuilder. Aumentemos el valor a 1000000 y veamos (no debería fallar, ¿verdad?):
El tiempo necesario para operar el tipo java.lang.StringBuffer es: 265 milisegundos El tiempo necesario para operar el tipo java.lang.StringBuilder es: 219 milisegundos
Hay menos diferencias y los resultados son muy estables. Veámoslo un poco más grande, ttime = 5000000:
・・・・・・ Excepción en el hilo "principal" java.lang.OutOfMemoryError: espacio de almacenamiento dinámico de Java ・・・・・・
Jaja, olvídalo, no lo probaré más. Básicamente, el rendimiento es StringBuilder > StringBuffer > String.