Diferencia de almacenamiento de cadenas en profundidad entre iguales y ==

Para iguales y ==, creo que todo el mundo está muy familiarizado con él. Para empezar, la clase principal Object de todas las clases tiene el método equals y la implementación interna es ==.

Sin embargo, los objetos tienen tres características principales: encapsulación, herencia y polimorfismo. Después de que muchas clases heredan la clase Object, encapsulan diferentes atributos según sea necesario. Naturalmente, no se puede realizar directamente ==. Esto es solo una comparación de direcciones, sin sentido , por lo que varias subclases tienen sus propias implementaciones. Por ejemplo, es igual en la clase Fecha compara el tiempo, es igual en HashMap Node <K, V> compara direcciones y también compara valores. Si alguna es igual, devuelve verdadero.

Por supuesto, normalmente encontramos más iguales y == en String. Pero para ser honesto, quien use == en el código usa igual, nada que decir, ¡seguro!

Echemos un vistazo a la implementación de iguales en String:

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

Este código no es difícil: primero compara si las dos cadenas son iguales, compara las direcciones y luego compara si las matrices de valores en la cadena son iguales. Siempre que una de las dos condiciones sea verdadera, equals devuelve verdadero.

De hecho, todo el mundo sabe que escribir código no provocará errores en iguales en String. ¿Por qué tanta gente está dispuesta a distinguir iguales de ==? A menudo hago preguntas en las entrevistas, de lo contrario, ¿quién irá a las raíces y entrará en pánico?

La estimación de que los encuentros de novatos más elementales es lo que es igual a y == en String, ¿cuál es la diferencia, se pueden intercambiar? ¿Qué? La respuesta es fácil de ver en el código fuente,

Luego crece un poco, solo para juzgar si el == de unas pocas cadenas es verdadero o falso.

Más adelante, en los aperitivos de la entrevista, es posible que encuentre preguntas sobre el almacenamiento de cadenas.

Hablemos del juicio sobre el almacenamiento y la igualdad de cadenas.

Todo el mundo conoce la estructura de almacenamiento subyacente de JMM, que simplemente se divide en memoria de pila, memoria de pila, área de método, grupo constante, registros y similares. Hoy nos centramos en String, por lo que principalmente estudiamos la memoria de pila, la memoria de pila y el grupo constante.

De hecho, el grupo de constantes también es un área abierta en la memoria del montón, y el almacenamiento de datos se encuentra principalmente en la memoria del montón.

Echemos un vistazo al proceso de creación y almacenamiento de cadenas.

String str = new String("abc");

Crea un nuevo objeto String y completa la tarea abc. ¿Qué tipo de proceso de creación atravesó?

En primer lugar, esta operación definitivamente generará una cadena "abc". Cree una nueva cadena en la pila de memoria como referencia al objeto.

A continuación, se crea la memoria del montón y se crea un objeto String con un valor de "abc". Finalmente, es para comprobar si hay una cadena "abc" en el pool constante, si no, crea una nueva, si la hay, ignórala.

Este es un proceso de creación simple, tan bueno, ahora miramos un ejemplo específico:

 

Como se muestra en la figura anterior, se han creado 5 objetos, y los veremos uno por uno.

El primero es crear una referencia de objeto s1, crear un "abc" en el grupo de constantes, también se debe crear un objeto en la memoria del montón, pero no hay referencia, se reciclará el siguiente GC.

En segundo lugar, se crea una referencia de objeto s2, se crea un objeto en el montón, "abc" ya está en el grupo constante y no se está creando.

En tercer lugar, se crea una referencia s3 de un objeto, se crean "a", "bc" y "abc" en el montón, pero no hay referencias a "a" y "bc", y gc se reciclará la próxima vez. "Abc" en el grupo constante ya existe y no se creará, se crearán "a" y "bc", pero no hay ninguna referencia y se reciclará pronto.

En cuarto lugar, se crea una referencia de objeto s4, se crea un objeto en el montón, ya hay "abc" en el grupo de constantes y no se está creando, y luego la cadena en el grupo de constantes se obtiene usando el intern () método.

En quinto lugar, se crea una referencia s5 de un objeto. Se crea un objeto en el montón, pero no se hace referencia y apunta directamente a la cadena en el grupo constante.

Obviamente, tanto s1 como s5 apuntan a "abc" en el grupo constante, e intern () apunta al objeto creado por la cadena "abc" por primera vez, que son los mismos datos, y el resultado de usar == es también es cierto.

s2, s3 y s4 son todos un objeto, y el resultado de usar == debe ser falso.

Tal vez algunos amigos estén un poco confundidos, s4 también apunta al "abc" en el grupo constante, ¿por qué no puede ser == con s1?

Bien, echemos un vistazo al código fuente de intern ():

public native String intern()

Bueno, solo esta línea es un método nativo, y java no implementa la capa inferior. Pero no importa, podemos encontrar el resultado que queremos de esta línea.

Echemos un vistazo al proceso de creación de s4. Primero, se crea una cadena de s4, y luego s4.intern (). Entonces, ¿existe una relación entre s4.intern () y s4? ¿Es solo una cadena de piscina constante? Y aún no hay asignación. El método intern () obviamente tiene un valor de retorno, ¿es bueno? Su valor de retorno no está asignado. Este código s4.intern () es casi un desperdicio de bien, pero está claro: voy a interferir con usted, ¿por qué?

Bueno, ejecutémoslo y echemos un vistazo:

public class Test {
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = new String("abc");
        String s3 = new String("a")+ new String("bc");
        String s4 = new String("abc"); s4.intern();
        String s5 = new String("abc").intern();
        System.out.print("s1==s5的结果");
        System.out.println(s1==s5);
        System.out.print("s1==s2的结果");
        System.out.println(s1==s2);
        System.out.print("s1==s3的结果");
        System.out.println(s1==s3);
        System.out.print("s1==s4的结果");
        System.out.println(s1==s4);
        System.out.print("s3==s4的结果");
        System.out.println(s3==s4);
    }
}

El resultado es, por supuesto, el mismo que el esperado. Además, no me mires escribiendo una descripción y el resultado se divide en dos líneas. Es decir, usar el signo "+" para conectar la cadena primero, luego comparar, luego no juegues nada, jeje, he pasado la etapa más avanzada, y he avanzado a un novato más avanzado. Bueno, veamos el resultado:

com.example.demo.Test
s1==s5的结果true
s1==s2的结果false
s1==s3的结果false
s1==s4的结果false
s3==s4的结果false

Process finished with exit code 0

Los estudiantes interesados ​​pueden depurarlo y verán que esta cadena de creación tiene una dirección Es fácil ver cómo es.

De acuerdo, detengámonos aquí hoy ~

Supongo que te gusta

Origin blog.csdn.net/zsah2011/article/details/105421652
Recomendado
Clasificación