¿Qué es String Interning en Java, cuándo debo usarlo y por qué ?
java
string
string-interning
saplingPro
fuente
fuente
String a = new String("abc");
String b = new String("abc");
entoncesa.intern() == b.intern()
String.intern()
dependeClassLoader
, es decir, hacer diferentes cargador de clases de la creación de "diferentes"String
s, causando diferentesintern
s?Respuestas:
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#intern ()
Básicamente, hacer String.intern () en una serie de cadenas asegurará que todas las cadenas que tengan el mismo contenido compartan la misma memoria. Entonces, si tiene una lista de nombres en los que "juan" aparece 1000 veces, al internarse se asegura de que solo se le asigne una memoria a "juan".
Esto puede ser útil para reducir los requisitos de memoria de su programa. Pero tenga en cuenta que JVM mantiene la memoria caché en una agrupación de memoria permanente, que generalmente tiene un tamaño limitado en comparación con el montón, por lo que no debe usar el interno si no tiene demasiados valores duplicados.
Más sobre las restricciones de memoria de usar intern ()
- De: http://www.codeinstructions.com/2009/01/busting-javalangstringintern-myths.html
Desde JDK 7 (quiero decir en HotSpot), algo ha cambiado.
- Desde Java SE 7 Características y mejoras
Actualización: las cadenas internadas se almacenan en el montón principal desde Java 7 en adelante. http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html#jdk7changes
fuente
char[]
lugar deString
texto sensible y ponerlo a cero tan pronto como ya no sea necesario.Hay algunas preguntas de "entrevista pegadiza", como por qué te haces igual. si ejecuta el siguiente código.
Si desea comparar cadenas, debe usarlas
equals()
. Lo anterior imprimirá igual porque el compiladortestString
ya lo ha internado . Puede internar las cadenas usted mismo utilizando el método interno como se muestra en las respuestas anteriores ...fuente
equals
método. Es posible que desee agregar unanew String()
comparación para mostrar la distinción más claramente.JLS
JLS 7 3.10.5 lo define y da un ejemplo práctico:
JVMS
JVMS 7 5.1 dice que el internado se implementa de manera mágica y eficiente con una
CONSTANT_String_info
estructura dedicada (a diferencia de la mayoría de los otros objetos que tienen representaciones más genéricas):Bytecode
Vamos a descompilar algunos bytecode de OpenJDK 7 para ver la internación en acción.
Si descompilamos:
tenemos en el grupo constante:
y
main
:Tenga en cuenta cómo:
0
y3
:ldc #2
se carga la misma constante (los literales)12
: se crea una nueva instancia de cadena (con un#2
argumento)35
:a
yc
se comparan como objetos normales conif_acmpne
La representación de cadenas constantes es bastante mágica en el código de bytes:
new String
. ej. )y la cita JVMS anterior parece decir que siempre que el Utf8 apuntado es el mismo, se cargan instancias idénticas
ldc
.He realizado pruebas similares para campos y:
static final String s = "abc"
apunta a la tabla constante a través del atributo ConstantValueldc
Conclusión : existe un soporte directo de bytecode para el conjunto de cadenas y la representación de la memoria es eficiente.
Bonificación: compárelo con el grupo Integer , que no tiene soporte directo de bytecode (es decir, no
CONSTANT_String_info
analógico).fuente
Actualización para Java 8 o más . En Java 8, el espacio PermGen (generación permanente) se elimina y se reemplaza por Meta Space. La memoria del conjunto de cadenas se mueve al montón de JVM.
En comparación con Java 7, el tamaño del grupo de cadenas aumenta en el montón. Por lo tanto, tiene más espacio para cadenas internalizadas, pero tiene menos memoria para toda la aplicación.
Una cosa más, ya sabías que al comparar 2 (referencias de) objetos en Java,
==
"se usa para comparar la referencia de objeto"equals
, se usa para comparar el contenido del objeto.Vamos a ver este código:
Resultado:
value1 == value2
---> verdaderovalue1 == value3
---> falsovalue1.equals(value3)
---> verdaderovalue1 == value3.intern()
---> verdaderoEs por eso que debes usar '
equals
' para comparar objetos de 2 cadenas. Y así es comointern()
es útil.fuente
El internamiento de cadenas es una técnica de optimización del compilador. Si tiene dos literales de cadena idénticos en una unidad de compilación, el código generado garantiza que solo se haya creado un objeto de cadena para todas las instancias de ese literal (caracteres entre comillas dobles) dentro del ensamblaje.
Soy de origen C #, así que puedo explicar dando un ejemplo de eso:
salida de las siguientes comparaciones:
Nota 1 : Los objetos se comparan por referencia.
Nota 2 : typeof (int) .Name se evalúa mediante el método de reflexión, por lo que no se evalúa en tiempo de compilación. Aquí estas comparaciones se hacen en tiempo de compilación.
Análisis de los resultados: 1) verdadero porque ambos contienen el mismo literal y, por lo tanto, el código generado tendrá un solo objeto que haga referencia a "Int32". Ver nota 1 .
2) verdadero porque se verifica el contenido de ambos valores, que es el mismo.
3) FALSO porque str2 y obj no tienen el mismo literal. Ver nota 2 .
fuente
fuente
Del libro Deshmukh del Programador de Java SE 11 de OCP encontré la explicación más fácil para Interning, que fue la siguiente: como las cadenas son objetos y dado que todos los objetos en Java siempre se almacenan solo en el espacio de almacenamiento dinámico, todas las cadenas se almacenan en el espacio de almacenamiento dinámico. Sin embargo, Java mantiene las cadenas creadas sin usar la nueva palabra clave en un área especial del espacio de almacenamiento dinámico, que se denomina "grupo de cadenas". Java mantiene las cadenas creadas con la nueva palabra clave en el espacio de almacenamiento dinámico normal.
El propósito del conjunto de cadenas es mantener un conjunto de cadenas únicas. Cada vez que crea una nueva cadena sin usar la nueva palabra clave, Java verifica si la misma cadena ya existe en el grupo de cadenas. Si lo hace, Java devuelve una referencia al mismo objeto String y si no lo hace, Java crea un nuevo objeto String en el conjunto de cadenas y devuelve su referencia. Entonces, por ejemplo, si usa la cadena "hola" dos veces en su código como se muestra a continuación, obtendrá una referencia a la misma cadena. De hecho, podemos probar esta teoría comparando dos variables de referencia diferentes usando el operador == como se muestra en el siguiente código:
El operador == simplemente comprueba si dos referencias apuntan al mismo objeto o no y devuelve verdadero si lo hacen. En el código anterior, str2 obtiene la referencia al mismo objeto String que se creó anteriormente. Sin embargo, str3 y str4 obtienen referencias a dos objetos String completamente diferentes. Es por eso que str1 == str2 devuelve verdadero pero str1 == str3 y str3 == str4 devuelven falso. De hecho, cuando haces una nueva cadena ("hola"); se crean dos objetos String en lugar de solo uno si es la primera vez que se usa la cadena "hello" en cualquier parte del programa: uno en el grupo de cadenas debido al uso de una cadena entre comillas y uno en el espacio de almacenamiento dinámico normal porque del uso de nueva palabra clave.
La agrupación de cadenas es la forma en que Java guarda la memoria del programa al evitar la creación de múltiples objetos de cadena que contienen el mismo valor. Es posible obtener una cadena del conjunto de cadenas para una cadena creada con la nueva palabra clave mediante el método interno de String. Se llama "internamiento" de objetos de cadena. Por ejemplo,
fuente