descargar - ¿Qué es String Pool en Java?
java offline (4)
Esta pregunta ya tiene una respuesta aquí:
Estoy confundido acerca de StringPool en Java. Me encontré con esto mientras leía el capítulo String en Java. Por favor, ayúdame a entender, en términos simples, lo que realmente hace StringPool.
Comencemos con una cita de la especificación de la máquina virtual:
La carga de una clase o interfaz que contiene un literal String puede crear un nuevo objeto String (§2.4.8) para representar ese literal. Esto puede no ocurrir si el objeto String ya se ha creado para representar una ocurrencia previa de ese literal, o si el método String.intern se ha invocado en un objeto String que representa la misma cadena que el literal.
Esto puede no ocurrir : esta es una pista, que hay algo especial sobre los objetos String
. Por lo general, invocar un constructor siempre creará una nueva instancia de la clase. Este no es el caso con Strings, especialmente cuando los objetos String se ''crean'' con literales. Esas cadenas se almacenan en una tienda (pool) global, o al menos las referencias se mantienen en una agrupación, y cada vez que se necesita una nueva instancia de cadenas ya conocidas, la vm devuelve una referencia al objeto desde la agrupación. En pseudo código, puede ser así:
1: a := "one"
--> if(pool[hash("one")] == null) // true
pool[hash("one") --> "one"]
return pool[hash("one")]
2: b := "one"
--> if(pool[hash("one")] == null) // false, "one" already in pool
pool[hash("one") --> "one"]
return pool[hash("one")]
Entonces, en este caso, las variables a
y b
mantienen referencias al mismo objeto. En este caso, tenemos (a == b) && (a.equals(b)) == true
.
Este no es el caso si usamos el constructor:
1: a := "one"
2: b := new String("one")
Nuevamente, se crea "one"
en el conjunto pero luego creamos una nueva instancia a partir del mismo literal, y en este caso, lleva a (a == b) && (a.equals(b)) == false
Entonces, ¿por qué tenemos un grupo de cadenas? Las cadenas y especialmente los literales de cadena son ampliamente utilizados en el código típico de Java. Y ellos son inmutables. Y al ser inmutable, se permite cachear cadenas para ahorrar memoria y aumentar el rendimiento (menos esfuerzo para la creación, menos basura recolectada).
Como programadores, no tenemos que preocuparnos demasiado por el conjunto de cadenas, siempre que tengamos en cuenta:
-
(a == b) && (a.equals(b))
puede sertrue
ofalse
( siempre useequals
para comparar Cadenas) - No utilice el reflejo para cambiar el
char[]
respaldochar[]
de una Cadena (ya que no sabe quién está actualizando usando esa Cadena)
Cuando la JVM carga clases, o ve una cadena literal o alguna cadena de código intern
, agrega la cadena a una tabla de búsqueda en su mayoría oculta que tiene una copia de cada cadena. Si se agrega otra copia, el tiempo de ejecución la organiza de modo que todos los literales se refieran al mismo objeto de cadena. Esto se llama "internamiento". Si dices algo como
String s = "test";
return (s == "test");
volverá a ser true
, porque la primera y la segunda "prueba" son en realidad el mismo objeto. La comparación de cadenas internas de esta manera puede ser mucho, mucho más rápida que String.equals
, ya que hay una comparación de referencia única en lugar de un montón de comparaciones de caracteres.
Puede agregar una cadena al grupo llamando a String.intern()
, que le devolverá la versión agrupada de la cadena (que podría ser la misma cadena en la que está internándose, pero sería una locura confiar en eso - - a menudo no puede estar seguro exactamente qué código se ha cargado y ejecutar hasta ahora e internó la misma cadena). La versión agrupada (la cadena devuelta por el intern
) será igual a cualquier literal idéntico. Por ejemplo:
String s1 = "test";
String s2 = new String("test"); // "new String" guarantees a different object
System.out.println(s1 == s2); // should print "false"
s2 = s2.intern();
System.out.println(s1 == s2); // should print "true"
No creo que realmente haga mucho, parece que es solo un caché para literales de cadenas. Si tiene varias cadenas cuyos valores son los mismos, todos señalarán el mismo literal de cadena en el grupo de cadenas.
String s1 = "Arul"; //case 1
String s2 = "Arul"; //case 2
En el caso 1, el literal s1 se crea nuevamente y se guarda en el grupo. Pero en el caso 2, literal s2 refiere el s1, no creará uno nuevo en su lugar.
if(s1 == s2) System.out.println("equal"); //Prints equal.
String n1 = new String("Arul");
String n2 = new String("Arul");
if(n1 == n2) System.out.println("equal"); //No output.
Esto se imprime true
(aunque no usemos el método equals
: forma correcta de comparar cadenas)
String s = "a" + "bc";
String t = "ab" + "c";
System.out.println(s == t);
Cuando el compilador optimiza los literales de cadena, ve que tanto s
como t
tienen el mismo valor y, por lo tanto, solo necesita un objeto de cadena. Es seguro porque String
es inmutable en Java.
Como resultado, tanto s
como t
apuntan al mismo objeto y se guarda algo de memoria.
El nombre ''grupo de cadenas'' proviene de la idea de que todas las cadenas ya definidas se almacenan en algún ''grupo'' y antes de crear un nuevo compilador de objetos String
comprueba si dicha cadena ya está definida.