Referencia de cadena en la parte de revisión básica de java-java

Este blog es lo que resumí y pensé al revisar los conceptos básicos de Java. Está orientado y es rápido de entender y entrevistar.
Se refiere a mi blog anterior y al blog técnico de Meituan. Mire el resumen directamente al revisar

Diferentes formas y efectos de la creación de cadenas en Java

Dos formas comunes de crear cadenas en java

	String s1 = "abc";//我是方法1
	String s2 = new String("abc");//我是方法2
  • Para String s1 = "abc"; este método de creación de valor literal , JVM estipula que al crear, primero consulte el grupo de cadenas, si hay un objeto String con un valor de "abc", entonces el valor en el grupo de cadenas se devuelve directamente Un objeto de "abc", de lo contrario, se creará un objeto con un valor de "abc" en el grupo de cadenas y se devolverá el objeto. En resumen, ** en el grupo de cadenas, devuelve si lo hay, crea y devuelve si no, de todos modos, se devuelve desde el grupo de constantes de cadena. ** Aquí se puede determinar durante la compilación y poner en el grupo constante.
  • Para String s1 = new String ("abc"); este tipo de método de creación nuevo, JVM estipula que, en primer lugar, busque el objeto de cadena "abc" en el grupo de cadenas, si lo hay, luego cree "abc" sin el grupo " Este objeto, crea un objeto de cadena "abc" directamente en el montón, y luego devuelve la dirección del objeto "abc" en el montón; si no es así, primero crea un objeto de cadena "abc" en el grupo de cadenas, y luego crea un objeto de cadena "abc" en el montón y, a continuación, devuelve la dirección de este objeto de cadena "abc" en el montón. En resumen, en el grupo de cadenas, si hay uno, no se crea, y si no lo es, se crea. En cualquier caso, es el objeto String el que debe ser nuevo en el montón, y qué objeto en se devuelve el montón.

Bueno, aquí hemos sentado las bases para que cuando analicemos el problema, podamos empezar con buen pie.

Primero probemos lo anterior:

 String s1 = new String("abc");

P: ¿Cuántos objetos crea este código?
Respuesta: Si no hay "abc" en el grupo de cadenas, se crean dos, uno en el grupo de cadenas y otro en el montón; si hay "abc" en la cadena, solo se crea uno, que es el que está en el montón.

String s1 = "abc";

P: ¿Cuántos objetos crea este código?
Respuesta: Si no hay "abc" en el grupo de cadenas, se crea uno, que es el que está en el grupo de cadenas, si hay "abc" en la cadena, no se crea.

método interno

El método String.intern () es poner activamente el objeto String en el grupo de cadenas. Si la cadena ya existe, no se realiza ninguna operación y se devuelve el objeto en el grupo de cadenas. Si no existe, se coloca en el string pool., Y devuelve el objeto en el string pool.

En jdk7 y versiones posteriores, si no hay s en el grupo de cadenas antes de usar el método s.intern (), luego de usar el método interno, el grupo de constantes de cadena ** no se almacena en el valor literal de s, pero almacenado directamente Referencia as en el montón. ** Debido a que no es necesario almacenar un objeto en el grupo constante, la referencia en el montón se puede almacenar directamente.

Usemos este ejemplo para probar

	String s3 = new String("1") + new String("1");
    s3.intern();
    String s4 = "11";
    System.out.println(s3 == s4);

String s3 = new String ("1") + new String ("1");, este código ahora genera 2 objetos finales, que son el "1" en el grupo de constantes de cadena y la referencia s3 en JAVA Heap Object. Hay dos cadenas nuevas anónimas ("1") en el medio, no las discutiremos. En este momento, el contenido del objeto de referencia s3 es "11", pero no hay ningún objeto "11" en el grupo constante en este momento.
El siguiente código s3.intern (); es poner la cadena "11" en s3 en el grupo de constantes String, porque en este momento no hay una cadena "11" en el grupo de constantes, por lo que la práctica normal es seguir el jdk6 figure El punto clave es que el grupo de constantes en jdk7 ya no está en el área de Perm, y se ha realizado un ajuste para generar un objeto de "11" en el grupo de constantes como se indica en. No es necesario almacenar una copia del objeto en el grupo constante y la referencia en el montón se puede almacenar directamente. Esta referencia apunta al objeto al que hace referencia s3. Es decir, las direcciones de referencia son las mismas.
Finalmente, String s4 = "11"; "11" en este código se declara explícitamente, por lo que se creará directamente en el pool de constantes. Al crearlo, se encuentra que ya existe este objeto, y en este momento es una referencia al objeto de referencia s3. Entonces, la referencia s4 apunta a lo mismo que s3. Entonces, la comparación final s3 == s4 es verdadera.

A modo de comparación, si movemos el método interno hacia abajo una línea, será muy diferente

	String s3 = new String("1") + new String("1");
    String s4 = "11";
    s3.intern();
    System.out.println(s3 == s4);

Obviamente, no tenemos demasiado análisis como el anterior, no hay un objeto s3 en el grupo de constantes de cadena, s4 es un valor literal y "11" se crea directamente en el grupo de constantes de cadena, por lo que los dos no deben ser igual, y el resultado es falso.

La ubicación del grupo String

Antes de jdk1.8, el grupo de constantes de cadena estaba en el grupo de constantes de tiempo de ejecución y el grupo de constantes de tiempo de ejecución era parte del área de métodos. En las versiones anteriores a jdk1.8, el área de métodos se implementó utilizando el concepto de generación permanente y el específico la ubicación estaba en el montón en la memoria. Y
en jdk1.6 y versiones anteriores, el grupo de constantes de cadena está en la región de pila Perm, la clase de región de Perm es un área estática, información de contenido, grupo de constantes, etc. El método principal para almacenar algunos segmentos de clases cargadas, el tamaño predeterminado es solo 4m.
En jdk1.7, el grupo de constantes de cadena se ha movido del área de generación permanente al área de Java Heap normal.
Jdk1.8 y posteriores, usan metaespacio para lograrlo, usan memoria local.
Por qué mudarse El área de generación permanente es demasiado pequeña es una de las principales razones.

El grupo de constantes de cadena generalmente no se recolecta como basura, porque la intención original del grupo de cadenas es mejorar la eficiencia, reducir la sobrecarga e intentar hacer que los objetos String de uso común se utilicen directamente.

Así que el análisis de jdk1.6 es completamente diferente de los ejemplos de arriba y abajo Todos nuestros ejemplos aquí se basan en jdk1.8.
Para jdk1.6, al analizar, tenga en cuenta que el área de generación permanente y la memoria del montón no son lo mismo, de modo que cuando esté en prácticas, no se puede hacer referencia al objeto String en la memoria del montón, por lo que hay que volver a crear uno, por lo que los dos objetos son independiente.

Prueba de preguntas de entrevista relacionadas

Hablamos sobre el grupo de constantes de cadena arriba. Tenemos cierto conocimiento de la ubicación de los objetos String en la memoria de Java. Aquí hay algunos ejemplos para analizar y analizar. Estos ejemplos se pueden usar como algunas preguntas simples de entrevista.

Ejemplo 1: hay como máximo un objeto String con el mismo valor en el grupo de cadenas y se crea el valor literal

//采用字面值赋值
        String s1 = "abc";//存在于字符串池中的对象
        String s2 = "abc";//存在于字符串池中的对象
        System.out.println(s1 == s2);//true

Al principio, nuestro grupo de cadenas está vacío, primero cree un objeto String "abc" en el grupo de cadenas, y luego devuelva este objeto a s1, y luego, al inicializar s2, encontramos que ya hay "abc" en el grupo de cadenas. Luego, devuelva directamente el objeto a s2 en este momento, por lo que aquí nuestro resultado de salida es verdadero, es decir, s1 y s2 apuntan al mismo objeto.

Ejemplo 2: la nueva palabra clave crea una instancia de un objeto String

//采用new关键字创建一个字符串对象
        String s3 = new String("abc");//存在于堆中的对象
        String s4 = new String("abc");//存在于堆中的对象
        System.out.println(s3 == s4);//false

Al principio, nuestro grupo de cadenas está vacío. Al inicializar s3, primero hacemos un nuevo objeto "abc" en el montón, y luego consultamos el grupo de cadenas para encontrar que no existe tal objeto, así que lo colocamos y colocamos el objeto en el montón simplemente nuevo retorno. Luego, al inicializar s4, de manera similar, primero un nuevo objeto "abc" en el montón, y luego consulta el grupo de cadenas para encontrar que el objeto ya existe, por lo que no funciona, y devuelve el objeto en el montón que era nuevo. . Debido a que s3 y s4 apuntan respectivamente a un objeto en el montón, las direcciones de memoria deben ser desiguales. (El "abc" en el grupo de constantes de cadena no es igual a s3, s4, porque la dirección de memoria es diferente)

Ejemplo 3: empalme de cuerdas

//当字符串池中有abc时,true
        String s5 = "abc" + "def";//编译时就已经确定,这是从字符串池中返回的对象
        String s6 = "abcdef";//存在于字符串池中的对象
        String s7 = new String("abc") + new String("def");//运行时才生成,在堆里
        System.out.println(s5 == s6);//true
        System.out.println(s6 == s7);//false

De manera similar, la cadena está vacía al principio, nuestro s5 es una concatenación de dos cadenas literales. Aquí, debido a que es un valor literal, el compilador calcula directamente el resultado de la concatenación en tiempo de compilación y lo coloca en el grupo de cadenas, por lo que es equivalente Yu String s5 = "abcdef".
Y s7 es el empalme de dos objetos String. El compilador no puede reconocer el resultado de su empalme en tiempo de compilación, por lo que aquí está el empalme completado en tiempo de ejecución. Aquí, el objeto "abc" se crea primero en el montón y luego en el Se crea el objeto "def", y debido a que el objeto String no se puede cambiar, se crea una nueva cadena en el montón y se devuelve a s7.
¡Así que al final s5 == s6 y s7! = s6.
En una palabra: empalme de cadenas literal durante el tiempo de compilación, mientras que se cita el empalme de cadenas durante el tiempo de ejecución .

Ejemplo 4: Empalme de cadenas de objetos de cadena, la diferencia entre jdk9 y versiones anteriores, StringBuilder

        String s1 = "abc";
        String s2 = "def";
        String s3 = s1 + s2;

Echemos un vistazo a ese código. Con respecto a este código, muchos blogs y videos instructivos en Internet lo explicarán así: Aquí, la línea de código s3 en realidad primero crea una instancia de un objeto StringBuilder y luego llama a su método append para empalmar los valores de objeto de s1 y s2. El método tostring se llama en una cadena para devolver una cadena a s3, por lo que el objeto devuelto aquí está realmente en la memoria del montón.
Esta afirmación es cierta y también podemos verla mirando su archivo de código de bytes. Inserte la descripción de la imagen aquí
Pero, de hecho, este es el caso en la versión jdk anterior a jdk9.
Si usamos jdk9, este no es el caso. Con jdk9, el objeto StringBuilder ya no se instanciará, pero se devolverá un objeto String debido a la llamada dinámica. Por supuesto, esto todavía está en el montón. Lo probamos con las siguientes instrucciones de código de bytes.
Inserte la descripción de la imagen aquí
Aquí se utiliza la instrucción invokeDynamic.

Ejemplo 5: método interno

        String s1 = new String("abc");
        String s2 = s1.intern();
        String s3 = "abc";
        System.out.println(s2==s3);//true

El método String.intern (), el activo es el objeto String en el grupo de cadenas, si la cadena ya existe, no hay operación, y devuelve el objeto en el grupo de cadenas, si no, la cadena de caracteres en el grupo, Y devuelve el objeto en el grupo de cuerdas.
Tenga en cuenta aquí que pase lo que pase, lo que se devuelve es un objeto en el grupo de cadenas.
Entonces, el objeto de s1 es nuevo en la memoria del montón, mientras que el objeto de s2 es devuelto por el grupo de cadenas y s3 ​​también es devuelto por el grupo de cadenas, por lo que el resultado final es verdadero.

para resumir

Aquí hay algunas oraciones cortas para resumir para una revisión posterior:

  • El valor literal se colocará en el grupo de constantes en tiempo de compilación o consultará el grupo de constantes.
  • En el caso de new, el nuevo objeto debe estar en el montón de todos modos, y se devuelve el objeto en el montón, y el valor literal del mismo valor está garantizado en el grupo constante.
  • El empalme de valores literales es equivalente al valor literal en sí.
  • El empalme de nuevos objetos String se determina en tiempo de ejecución y el resultado de este empalme no se incluirá en el grupo constante.
  • El método interno coloca el objeto String en el grupo constante, no en el valor literal.

referencias

Artículo técnico de Meituan: Análisis en profundidad de String # intern
Mi propio blog anterior: jvm aprendiendo el grupo de constantes de cadenas de Java y las preguntas comunes de entrevistas simples de String

Supongo que te gusta

Origin blog.csdn.net/qq_34687559/article/details/112507110
Recomendado
Clasificación