recorrer ordenado metodos example entre elementos diferencia adicionar java string hashmap string-interning

ordenado - Java, HashMaps y usar cadenas como claves: ¿el valor de cadena se almacena dos veces?



recorrer hashmap java foreach (3)

Si tengo un HashMap que se ve así:

HashMap<String, MyObject>

donde la clave String es un campo en MyObject , ¿este valor de cadena se almacena dos veces?

Entonces cuando agrego entradas:

_myMap.put(myObj.getName(), myObj);

¿Estoy usando el doble del tamaño de cadena en términos de memoria? ¿O Java hace algo inteligente detrás de escena?

Gracias


Java usa la referencia, por lo que es solo un puntero a la cadena que almacena dos veces. Así que no tiene que preocuparse si su cadena es enorme, igual será la misma cantidad de memoria que se utiliza.


Las cadenas son inmutables, pero se aplican las referencias pasadas. Por lo tanto, no requerirá el doble de memoria.


A menos que esté creando un nuevo valor String en getName() , no está duplicando el uso de memoria.

Aquí hay algunos ejemplos para aclarar cosas:

String s1 = "Some really long string!"; String s2 = s1; assert s1.equals(s2);

Aquí, s1 == s2 ; se refieren a la misma instancia de String . Su uso de memoria es de 2 variables de referencia (no es gran cosa), 1 instancia de String y 1 char[] respaldo char[] (la parte que ocupa la memoria).

String s1 = "Some really long string!"; String s2 = new String(s1); assert s1.equals(s2);

Aquí, s1 != s2 ; se refieren a diferentes instancias de String . Sin embargo, dado que las cadenas son inmutables, el constructor sabe que pueden compartir la misma matriz de caracteres. Su uso de memoria es de 2 variables de referencia, 2 instancias String (todavía no es gran cosa, porque ...) y 1 copia de seguridad char[] .

String s1 = "Some really long string!"; String s2 = new String(s1.toCharArray()); assert s1.equals(s2);

Aquí, al igual que antes, s1 != s2 . Se usa un constructor diferente, esta vez, sin embargo, toma un char[] lugar. Para garantizar la inmutabilidad, toCharArray() debe devolver una copia defensiva de su matriz interna (de ese modo, cualquier cambio en la matriz devuelta no mutaría el valor de la cadena).

[ toCharArray () devuelve] una matriz de caracteres recién asignada cuya longitud es la longitud de esta cadena y cuyos contenidos se inicializan para contener la secuencia de caracteres representada por esta cadena.

Para empeorar las cosas, el constructor también debe copiar defensivamente la matriz dada en su matriz interna de respaldo, nuevamente para asegurar la inmutabilidad. Esto significa que ¡ hasta 3 copias de la matriz de caracteres pueden vivir en la memoria al mismo tiempo! 1 de ellos será recogido en el momento, así que el uso de la memoria es de 2 variables de referencia, 2 instancias String y 2 copias de respaldo char[] ! ¡AHORA tu uso de memoria se duplica!

Volviendo a su pregunta, siempre y cuando no esté creando un nuevo valor String en getName() (es decir, si simplemente return this.name; ), entonces está bien. Sin embargo, si está haciendo una concatenación simple (por ejemplo, return this.firstName + this.lastName; ), ¡duplicará el uso de la memoria!

El siguiente código ilustra mi punto:

public class StringTest { final String name; StringTest(String name) { this.name = name; } String getName() { return this.name; // this one is fine! // return this.name + ""; // this one causes OutOfMemoryError! } public static void main(String args[]) { int N = 10000000; String longString = new String(new char[N]); StringTest test = new StringTest(longString); String[] arr = new String[N]; for (int i = 0; i < N; i++) { arr[i] = test.getName(); } } }

Primero debe verificar que se ejecuta el código anterior ( java -Xmx128m StringTest ) sin lanzar ninguna excepción. Luego, modifique getName() para return this.name + ""; y ejecutarlo de nuevo. Esta vez obtendrá un OutOfMemoryError .