manejo - metodo string java
Es String Literal Pool una colección de referencias al objeto String, o una colección de objetos (1)
Estoy completamente confundido después de leer el artículo en el sitio javaranch por Corey McGlone, el autor de The SCJP Tip Line. nombrada Strings, literalmente, y la guía SCJP Java 6 Programmer Guide por Kathy Sierra (co-founder of javaranch) and Bert Bates
.
Trataré de citar lo que el Sr. Corey y la Sra. Kathy Sierra han citado sobre String Literal Pool.
1. Según el Sr. Corey McGlone:
String Literal Pool es una colección de referencias que apunta a los String Objects.
String s = "Hello";
(Suponga que no hay ningún objeto en el montón denominado "Hola"), creará un objeto de cadena"Hello"
en el montón, y colocará una referencia a este objeto en el conjunto literal de cadenas (tabla de constantes)String a = new String("Bye");
(Suponga que no hay ningún objeto en el Heap llamado "Bye", elnew
operador obligará a la JVM a crear un objeto en el Heap.
Ahora la explicación del operador "new"
para la creación de un String y su referencia es un poco confusa en este artículo, así que estoy poniendo el código y la explicación del artículo en sí, tal como está debajo.
public class ImmutableStrings
{
public static void main(String[] args)
{
String one = "someString";
String two = new String("someString");
System.out.println(one.equals(two));
System.out.println(one == two);
}
}
En este caso, en realidad terminamos con un comportamiento ligeramente diferente debido a la palabra clave "new."
En tal caso, las referencias a los dos literales de Cadena todavía se ponen en la tabla constante (el Conjunto Literal de Cadenas), pero, cuando se llega a la palabra clave "new,"
la JVM está obligada a crear un nuevo objeto Cadena en ejecución. tiempo, en lugar de usar el de la tabla constante.
Aquí está el diagrama que lo explica ...
Entonces, ¿significa que el conjunto literal de cadenas también tiene una referencia a este objeto?
Aquí está el enlace al artículo de Corey McGlone
http://www.javaranch.com/journal/200409/Journal200409.jsp#a1
2. Según Kathy Sierra y Bert Bates en el libro SCJP:
Para que Java sea más eficiente en cuanto a la memoria, la JVM aparta un área especial de memoria llamada "conjunto constante de cadenas", cuando el compilador encuentra un Literal de cadenas, comprueba el grupo para ver si ya existe o no una cadena idéntica. Si no, entonces crea un nuevo objeto literal String.
String s = "abc";
// Crea un objeto String y una variable de referencia ....eso está bien, pero ahora la declaración siguiente me confundió.
String s = new String("abc")
// Crea dos objetos y una variable de referencia.Dice en el libro que .... un nuevo objeto String en la memoria normal (sin agrupamiento), y "s" se referirá a él ... mientras que un adicional, el literal "abc" se colocará en el conjunto.
Las líneas anteriores en el libro colisionan con la del artículo de Corey McGlone.
Si String Literal Pool es una colección de referencias al objeto String como lo mencionó Corey McGlone, entonces, ¿cómo es que el objeto literal "abc" se colocará en el conjunto, como se menciona en el libro?
Y donde reside este String Literal Pool.
Por favor, aclare esta duda, aunque no importará demasiado al escribir un código, pero es muy importante desde el punto de vista de la administración de la memoria, y esa es la razón por la que quiero aclarar este fundamento.
Creo que el punto principal para entender aquí es la distinción entre String
objeto String
Java y su contenido - char[]
en el campo de value
privado . String
es básicamente un envoltorio alrededor de la matriz char[]
, que lo encapsula y hace que sea imposible modificarlo para que la String
permanezca inmutable. Además, la clase String
recuerda qué partes de esta matriz se utilizan realmente (ver a continuación). Esto significa que puede tener dos objetos String
diferentes (bastante livianos) apuntando al mismo char[]
.
Le mostraré algunos ejemplos, junto con hashCode()
de cada String
y hashCode()
del campo de char[] value
interno char[] value
(lo llamaré texto para distinguirlo de la cadena). Finalmente, mostraré javap -c -verbose
output, junto con el pool constante para mi clase de prueba. No confunda el grupo de constante de clases con el grupo de cadenas literales. No son lo mismo. Consulte también Comprender la salida de javap para el conjunto de constantes .
Requisitos previos
Con el propósito de probar, creé un método de utilidad que rompe String
encapsulación de Cadenas:
private int showInternalCharArrayHashCode(String s) {
final Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
return value.get(s).hashCode();
}
Imprimirá hashCode()
del char[] value
, lo que nos ayudará a entender si este String
particular apunta al mismo texto char[]
o no.
Dos literales de cadena en una clase
Comencemos por el ejemplo más simple.
Código Java
String one = "abc";
String two = "abc";
Por cierto, si simplemente escribe "ab" + "c"
, el compilador de Java realizará la concatenación en tiempo de compilación y el código generado será exactamente el mismo. Esto solo funciona si todas las cadenas se conocen en tiempo de compilación.
Grupo constante de clases
Cada clase tiene su propio conjunto constante : una lista de valores constantes que pueden reutilizarse si ocurren varias veces en el código fuente. Incluye cadenas comunes, números, nombres de métodos, etc.
Aquí están los contenidos del grupo constante en nuestro ejemplo anterior.
const #2 = String #38; // abc
//...
const #38 = Asciz abc;
Lo importante a tener en cuenta es la distinción entre String
objeto constante String
(n #2
) y el texto codificado en Unicode "abc"
(n #38
) al que apunta el hilo.
Código de bytes
Aquí está el código de bytes generado. Tenga en cuenta que tanto one
como two
referencias se asignan con la misma constante #2
apuntando a la cadena "abc"
:
ldc #2; //String abc
astore_1 //one
ldc #2; //String abc
astore_2 //two
Salida
Para cada ejemplo estoy imprimiendo los siguientes valores:
System.out.println(showInternalCharArrayHashCode(one));
System.out.println(showInternalCharArrayHashCode(two));
System.out.println(System.identityHashCode(one));
System.out.println(System.identityHashCode(two));
No es de sorprender que ambos pares sean iguales:
23583040
23583040
8918249
8918249
Lo que significa que no solo ambos objetos apuntan a la misma char[]
(el mismo texto debajo) por lo que la prueba equals()
pasará. ¡Pero aún más, one
y two
son exactamente las mismas referencias! Entonces one == two
es verdad también. Obviamente, si one
y two
apuntan al mismo objeto, entonces one.value
y two.value
deben ser iguales.
Literal y new String()
Código Java
Ahora el ejemplo que todos esperamos: un string literal y un nuevo String
usando el mismo literal. ¿Cómo funcionará esto?
String one = "abc";
String two = new String("abc");
El hecho de que la constante "abc"
se use dos veces en el código fuente debería darle alguna pista ...
Grupo constante de clases
Lo mismo que arriba.
Código de bytes
ldc #2; //String abc
astore_1 //one
new #3; //class java/lang/String
dup
ldc #2; //String abc
invokespecial #4; //Method java/lang/String."<init>":(Ljava/lang/String;)V
astore_2 //two
¡Mira cuidadosamente! El primer objeto se crea de la misma manera que arriba, no es sorpresa. Simplemente toma una referencia constante a String
( #2
) ya creado del conjunto constante. Sin embargo, el segundo objeto se crea mediante una llamada de constructor normal. ¡Pero! La primera String
se pasa como un argumento. Esto puede ser descompilado a:
String two = new String(one);
Salida
La salida es un poco sorprendente. El segundo par, que representa referencias al objeto String
es comprensible: creamos dos objetos String
, uno se creó para nosotros en el conjunto constante y el segundo se creó manualmente para two
. Pero ¿por qué, en la Tierra, el primer par sugiere que ambos objetos String
apuntan a la misma matriz de char[] value
?
41771
41771
8388097
16585653
Se vuelve claro cuando se observa cómo funciona el constructor String(String)
(muy simplificado aquí):
public String(String original) {
this.offset = original.offset;
this.count = original.count;
this.value = original.value;
}
¿Ver? Cuando está creando un nuevo objeto String
basado en uno existente, reutiliza el char[] value
. String
son inmutables, no es necesario copiar la estructura de datos que se sabe que nunca se modificará.
Creo que esta es la clave de su problema: incluso si tiene dos objetos String
, aún podrían señalar los mismos contenidos. Y como pueden ver, el objeto String
sí es bastante pequeño.
Modificación en tiempo de ejecución e intern()
Código Java
Digamos que inicialmente usaste dos cadenas diferentes pero después de algunas modificaciones son todas iguales:
String one = "abc";
String two = "?abc".substring(1); //also two = "abc"
El compilador de Java (al menos el mío) no es lo suficientemente inteligente como para realizar dicha operación en tiempo de compilación, eche un vistazo:
Grupo constante de clases
De repente, terminamos con dos cadenas constantes que apuntan a dos textos constantes diferentes:
const #2 = String #44; // abc
const #3 = String #45; // ?abc
const #44 = Asciz abc;
const #45 = Asciz ?abc;
Código de bytes
ldc #2; //String abc
astore_1 //one
ldc #3; //String ?abc
iconst_1
invokevirtual #4; //Method String.substring:(I)Ljava/lang/String;
astore_2 //two
La cuerda del puño está construida como de costumbre. El segundo se crea cargando primero la cadena constante "?abc"
y luego llamando a la substring(1)
en ella.
Salida
No es de sorprender aquí, tenemos dos cadenas diferentes, apuntando a dos diferentes char[]
textos en la memoria:
27379847
7615385
8388097
16585653
Bueno, los textos no son realmente diferentes , el método equals()
seguirá siendo true
. Tenemos dos copias innecesarias del mismo texto.
Ahora deberíamos ejecutar dos ejercicios. Primero, intente ejecutar:
two = two.intern();
antes de imprimir códigos hash. ¡No solo one
y two
apuntan al mismo texto, sino que son la misma referencia!
11108810
11108810
15184449
15184449
Esto significa que one.equals(two)
las one.equals(two)
y one == two
. También guardamos algo de memoria porque el texto "abc"
aparece solo una vez en la memoria (la segunda copia será basura).
El segundo ejercicio es ligeramente diferente, mira esto:
String one = "abc";
String two = "abc".substring(1);
Obviamente, one
y two
son dos objetos diferentes, que apuntan a dos textos diferentes. ¿Pero cómo es que el resultado sugiere que ambos apuntan a la misma matriz de caracteres char[]
?
23583040
23583040
11108810
8918249
Dejaré la respuesta para ti. Le enseñará cómo funciona substring()
, cuáles son las ventajas de dicho enfoque y cuándo puede ocasionar grandes problemas .