Me preguntaron sobre cadenas inmutables en Java. Me encargaron escribir una función que concatenara varias "a" en una cadena.
Lo que escribí:
public String foo(int n) {
String s = "";
for (int i = 0; i < n; i++) {
s = s + "a"
}
return s;
}
Luego me preguntaron cuántas cadenas generaría este programa, suponiendo que la recolección de basura no ocurra. Mis pensamientos para n = 3 eran
- ""
- "un"
- "un"
- "Automóvil club británico"
- "un"
- "aaa"
- "un"
Esencialmente se crean 2 cadenas en cada iteración del bucle. Sin embargo, la respuesta fue n 2 . ¿Qué cadenas se crearán en la memoria con esta función y por qué es así?
Respuestas:
Las cadenas 1 (
""
) y 2 ("a"
) son las constantes en el programa, no se crean como parte de las cosas sino que se 'internan' porque son constantes que el compilador conoce. Lea más sobre esto en String interning en Wikipedia.Esto también elimina las cadenas 5 y 7 del recuento, ya que son lo mismo
"a"
que la Cadena # 2. Esto deja las cadenas # 3, # 4 y # 6. La respuesta es "se crean 3 cadenas para n = 3" utilizando su código.El recuento de n 2 obviamente es incorrecto porque en n = 3, esto sería 9 e incluso por su respuesta en el peor de los casos, eso fue solo 7. Si sus cadenas no internadas eran correctas, la respuesta debería haber sido 2n + 1.
Entonces, la pregunta de cómo debe hacer esto?
Como la cadena es inmutable , desea algo mutable, algo que pueda cambiar sin crear nuevos objetos. Ese es el StringBuilder .
Lo primero a tener en cuenta son los constructores. En este caso, sabemos cuánto tiempo durará la cadena, y hay un constructor, lo
StringBuilder(int capacity)
que significa que asignamos exactamente lo que necesitamos.A continuación,
"a"
no necesita ser una cadena , sino que puede ser un personaje'a'
. Esto tiene un aumento de rendimiento menor cuando se llamaappend(String)
vsappend(char)
: con elappend(String)
método, necesita descubrir cuánto tiempo dura la cadena y hacer algo de trabajo en eso. Por otro lado,char
siempre tiene exactamente un carácter de largo.Las diferencias de código se pueden ver en StringBuilder.append (String) vs StringBuilder.append (char) . No es algo de lo que preocuparse demasiado , pero si está tratando de impresionar al empleador, es mejor utilizar las mejores prácticas posibles.
Entonces, ¿cómo se ve esto cuando lo juntas?
Se han creado un StringBuilder y un String. No se necesitan cadenas adicionales para ser internado.
Escriba algunos otros programas simples en Eclipse. Instala pmd y ejecútalo en el código que escribes. Tenga en cuenta de qué se queja y arregle esas cosas. Hubiera encontrado la modificación de una Cadena con + en un bucle, y si la hubiera cambiado a StringBuilder, tal vez habría encontrado la capacidad inicial, pero ciertamente detectaría la diferencia entre
.append("a")
y.append('a')
fuente
En cada iteración,
String
el+
operador crea un nuevo y se le asignas
. Después del regreso, todos ellos, excepto el último, se recolectan como basura.Las constantes de cadena les gusta
""
y"a"
no se crean cada vez, estas son cadenas internas . Como las cadenas son inmutables, se pueden compartir libremente; Esto le sucede a las constantes de cadena.Para concatenar cadenas de manera eficiente, use
StringBuilder
.fuente
Como MichaelT explica en su respuesta, su código asigna cadenas O (n). Pero también asigna O (n 2 ) bytes de memoria y se ejecuta en tiempo O (n 2 ).
Asigna O (n 2 ) bytes, porque las cadenas que está asignando tienen longitudes 0, 1, 2, ..., n-1, n, que suman a (n 2 + n) / 2 = O (n 2 ).
El tiempo también es O (n 2 ), porque la asignación de la cadena i-ésima requiere la copia de la cadena (i-1), que tiene una longitud i-1. Esto significa que cada byte asignado debe copiarse, lo que llevará tiempo O (n 2 ).
¿Quizás esto es lo que querían decir los entrevistadores?
fuente