Original: ¿Crear una cadena Java usando “ ” o Constructor? Por X Wang En Java, se pueden crear cadenas utilizando dos métodos:
String x = "abc";
String y = new String("abc");
¿Cuál es la diferencia entre usar comillas dobles y usar un constructor?
1. Comillas dobles vs. Constructor
Esta pregunta puede responderse observando dos ejemplos sencillos. Ejemplo 1:String a = "abcd";
String b = "abcd";
System.out.println(a == b); // True
System.out.println(a.equals(b)); // True
a==b
Es cierto porque a
ambos b
se refieren al mismo objeto: una cadena declarada como literal (literal de cadena a continuación) en el área del método (remitimos al lector a la fuente de nuestro recurso: Los 8 diagramas principales para comprender Java , diagrama 8). Cuando el mismo literal de cadena se crea más de una vez, solo se almacena una copia de la cadena en la memoria, solo una instancia de la misma (en nuestro caso, "abcd"). Esto se llama "internación de cadenas". Todas las constantes de cadena procesadas en tiempo de compilación se internan automáticamente en Java. Ejemplo 2:
String c = new String("abcd");
String d = new String("abcd");
System.out.println(c == d); // False
System.out.println(c.equals(d)); // True
c==d
falso porque c
se d
refieren a dos objetos diferentes en la memoria (en el montón). Diferentes objetos siempre tienen diferentes referencias. Este diagrama ilustra las dos situaciones descritas anteriormente:
2. Cadenas internas en la etapa de ejecución del programa.
El autor agradece a LukasEder (el comentario a continuación es suyo): El internamiento de cadenas también puede ocurrir durante la ejecución del programa, incluso si se crean dos cadenas usando constructores:String c = new String("abcd").intern();
String d = new String("abcd").intern();
System.out.println(c == d); // Now true
System.out.println(c.equals(d)); // True
3. Cuándo usar comillas dobles y cuándo usar constructores
Debido al hecho de que el literal "abcd" siempre es de tipo String, el uso de un constructor creará un objeto adicional innecesario. Por lo tanto, se deben usar comillas dobles si solo necesita crear una cadena. Si realmente necesitas crear un nuevo objeto en el montón, debes usar un constructor. Los casos de uso se muestran aquí (original) . (Proporciono el texto traducido a continuación. Pero aun así recomiendo encarecidamente que se familiarice con el código de los comentaristas en este enlace).El método substring() en JDK 6 y JDK 7
El método substring() en JDK 6 y JDK 7 por X Wang El métodosubstring(int beginIndex, int endIndex)
en JDK 6 y JDK 7 es diferente. Conocer estas diferencias puede ayudarle a utilizar mejor este método. Para facilitar la lectura, a continuación substring()
nos referiremos a la sintaxis completa, es decir. substring(int beginIndex, int endIndex)
.
1. ¿Qué hace la subcadena()?
El métodosubstring(int beginIndex, int endIndex)
devuelve una cadena que comienza con el número de carácter beginIndex
y termina con el número de carácter endIndex-1
.
String x = "abcdef";
x = x.substring(1,3);
System.out.println(x);
Producción:
bc
2. ¿Qué sucede cuando se llama a substring()?
Quizás sepas que, debido a la inmutabilidadx
, al asignar a x el resultado de x.substring(1,3)
, x
apunta a una fila completamente nueva (ver diagrama): Sin embargo, este diagrama no es completamente correcto; no demuestra lo que realmente está sucediendo en el montón. Lo que realmente sucede cuando se llama substring()
es diferente en JDK 6 y JDK 7.
3. subcadena() en JDK 6
El tipo de cadena es compatible con el tipo de matrizchar
. En JDK 6, la clase String
contiene 3 campos: char value[]
, int offset
, int count
. Se utilizan para almacenar la matriz real de caracteres, el índice del primer carácter de la matriz y el número de caracteres en la línea. Cuando se llama al método substring()
, crea una nueva fila, pero el valor de la variable aún apunta a la misma matriz en el montón. La diferencia entre dos cadenas es su número de caracteres y el valor de índice del carácter inicial de la matriz. El siguiente código está simplificado y solo contiene lo básico para demostrar el problema.
//JDK 6
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
public String substring(int beginIndex, int endIndex) {
//check boundary
return new String(offset + beginIndex, endIndex - beginIndex, value);
}
4. Problema causado por substring() en JDK 6
Si tiene una cadena MUY larga, pero solo necesita una pequeña parte, que obtiene cada vez que usasubstring()
. Esto causará problemas de ejecución, ya que solo necesitas una pequeña parte, pero aún así debes almacenar la cadena completa. Para JDK 6, la solución es el siguiente código, que convertirá la cadena en una subcadena real:
x = x.substring(x, y) + ""
El usuario STepeR formuló una pregunta (ver su comentario), y pareció necesario añadir el punto 4. "Problema causado substring()
en JDK 6" es un ejemplo más extenso. Espero que esta sea la respuesta y ayude a otros a descubrir rápidamente cuál es el problema. Aquí está el código:
String a = "aLongLongString";
String b = a.substring(1, 2);
String c = a.substring(2, 6);
Entonces, en JDK 7 b
, los objetos с
de tipo a String
creados llamando a un método substring()
en un objeto de tipo a String
harán referencia a dos matrices recién creadas en el montón: L
for b
, ongL
for c
. Estas dos nuevas matrices se almacenarán en el montón JUNTO con la matriz original aLongLongString
a la que hace referencia a. Aquellos. la matriz original no desaparece por ningún lado. Ahora volvamos a JDK 6. En JDK 6, un montón contiene una única matriz aLongLongString
. Después de ejecutar las líneas de código.
String b = a.substring(1, 2);
String c = a.substring(2, 6);
los objetos b
se refieren c
a la misma matriz en el montón, correspondiente al objeto a
: b
- a los elementos del 1.º índice al 2.º, c
- a los elementos del 2.º índice al 6.º (la numeración comienza desde 0, recordatorio). Aquellos. Obviamente, cualquier acceso adicional a las variables b
o c en JDK 6 en realidad dará como resultado que los elementos deseados de la matriz original se "cuenten" en el montón. En JDK 7, cualquier acceso adicional a variables b
o c provocará un acceso a las matrices más pequeñas necesarias que ya se han creado y "viven" en el montón. Aquellos. Claramente, JDK 7 usa físicamente más memoria en situaciones como esta. Pero imaginemos una posible opción: ciertas subcadenas de la variable se asignan a las variables b
, y en el futuro todos usarán solo ellas: objetos y . Ya nadie accede simplemente a la variable a; no hay referencias a ella (esto es lo que quiere decir el autor del artículo). Como resultado, en algún momento se activa el recolector de basura y (en la forma más general, por supuesto) obtenemos 2 situaciones diferentes: JDK 6 : el objeto se destruye (se recolecta basura) , PERO - la enorme matriz original en el montón está vivo; se utiliza constantemente y . JDK 7: el objeto a se destruye junto con la matriz original en el montón. Este es el punto en JDK 6 que puede provocar una pérdida de memoria. c
a
b
c
a
b
c
5. subcadena() en JDK 7
El método se ha mejorado en JDK 7. En JDK 7substring()
, en realidad crea una nueva matriz en el montón.
//JDK 7
public String(char value[], int offset, int count) {
//check boundary
this.value = Arrays.copyOfRange(value, offset, offset + count);
}
public String substring(int beginIndex, int endIndex) {
//check boundary
int subLen = endIndex - beginIndex;
return new String(value, beginIndex, subLen);
}
GO TO FULL VERSION