Java Interview Alchemy Series (1) | Análisis de preguntas comunes de entrevistas sobre String

por ejemplo:

public static void main(String[] args) {
    //基本数据类型
    int num1 = 100;
    int num2 = 100;
    System.out.println("num1 == num2 : " + (num1 == num2) + "\n");

    //引用类型,其中'System.identityHashCode'可以理解为打印对象地址
    String str1 = "mio4";
    String str2 = "mio4";
    System.out.println("str1 address : " + System.identityHashCode(str1));
    System.out.println("str2 address : " + System.identityHashCode(str1));
    System.out.println("str1 == str2 : " + (str1 == str2) + "\n");

    String str3 = new String("mio4");
    String str4 = new String("mio4");
    System.out.println("str3 address : " + System.identityHashCode(str3));
    System.out.println("str4 address : " + System.identityHashCode(str4));
    System.out.println("str3 == str4 : " + (str3 == str4));
}

Ejecute el código anterior, puede obtener los siguientes resultados:

num1 == num2: verdadero

dirección str1: 1639705018
dirección str2: 1639705018
str1 == str2: true

str3 address: 1627674070
str4 address: 1360875712
str3 == str4: false
Puede ver que las direcciones de memoria de str1 y str2 son 1639705018, así que use == para juzgar como verdadero,

Pero las direcciones de str3 y str4 son diferentes, por lo que el juicio es falso.

  1. método equals ()
    2.1 Clase de objeto equals ()
    En el lenguaje Java, todas las clases heredan de la superclase Object. También hay un método equals () en esta clase, así que echemos un vistazo a este método primero.

Se puede ver que este método es muy sencillo, consiste en comparar la dirección de memoria del objeto. Por lo tanto, cuando el objeto no anula este método, este método se usa de forma predeterminada, es decir, se compara el valor de la dirección de memoria del objeto. Pero clases como String y Integer se han reescrito como equals (). Tome String como ejemplo a continuación.

2.2 La clase de cadena es igual a ()

Obviamente, el método equals () de String solo compara su valor de datos, no la dirección de memoria del objeto.

Tome String como ejemplo para probar:

public static void main (String [] args) { String str1 = “mio4”; String str2 = "mio4";

    String str3 = new String("mio4");
    String str4 = new String("mio4");

    System.out.println("str1 address : " + System.identityHashCode(str1));
    System.out.println("str2 address : " + System.identityHashCode(str1));
    System.out.println("str1.equals(str2) : " + str1.equals(str2) + "\n");

    System.out.println("str3 address : " + System.identityHashCode(str3));
    System.out.println("str4 address : " + System.identityHashCode(str4));
    System.out.println("str3.equals(str4) : " + str3.equals(str4) + "\n");
}

El resultado de la prueba es el siguiente. Se puede ver que las direcciones de str3 y str4 son diferentes, pero debido a que el contenido de la cadena String es el mismo, el juicio igual es verdadero

dirección str1: 1639705018
dirección str2: 1639705018
str1.equals (str2): verdadero

str3 dirección: 1627674070
str4 dirección: 1360875712
str3.equals (str4): verdadero
3. método hashCode ()
3.1 ¿Por qué existe tal método? Escenarios de uso
en la colección Java (Colección) Hay tres tipos, uno es Lista, otro es Cola, los elementos del conjunto están ordenados, el elemento puede repetirse; luego hay una clase de Conjunto, elementos desordenados dentro del conjunto, Los elementos no se pueden repetir.

Entonces, aquí hay un problema más serio: si desea asegurarse de que los elementos no se repitan, ¿cuál debería ser la base para juzgar si dos elementos se repiten? Este es el método Object.equals. Sin embargo, si la verificación se realiza cada vez que se agrega un elemento, cuando hay muchos elementos, el número de comparaciones de los elementos agregados al conjunto será muy grande. En otras palabras, si ya hay 1000 elementos en la colección, cuando el elemento 1001 se agregue a la colección, llamará al método equals 1000 veces. Obviamente, esto reducirá en gran medida la eficiencia. Por lo tanto, Java utiliza el principio de tablas hash. De esta manera, usamos un algoritmo hash para calcular un valor para cada elemento que se almacenará en el conjunto, y luego calculamos la posición del elemento en la matriz en función del valor. Por lo tanto, cuando se agrega un nuevo elemento a la colección, se puede dividir en dos pasos:   
primero llame al método hashCode de este elemento y luego calcule la posición del elemento en la matriz en función del valor obtenido. Si no hay ningún elemento en esta posición, guárdelo directamente en esta posición;
si ya hay un elemento en esta posición, llame a su método equals para comparar con el nuevo elemento: si es el mismo, no se almacenará, de lo contrario, se almacenará Esta posición corresponde a la lista enlazada (la implementación de HashSet, HashMap y Hashtable en Java siempre coloca los elementos a la cabeza de la lista enlazada).
3.2 La asociación entre hashCode () y equals ()
 Premisa: Cuando se trata de hashCode, tienes que decir método equals, ambos métodos en la clase Object. Dado que la clase Object es la clase base de todas las clases, estos dos métodos se pueden anular en todas las clases.

Principio 1: Si x.equals (y) devuelve "verdadero", entonces el hashCode () de xey debe ser igual;
Principio 2: Si x.equals (y) devuelve "falso", entonces el hashCode () de xey tiene Puede ser igual o no;
Principio 3: Si el hashCode () de xey no son iguales, entonces x.equals (y) debe devolver "falso";
Principio 4: En términos generales, el método equals se llama a los usuarios , Y el método hashcode generalmente no es llamado por los usuarios;
Principio 5: Cuando un tipo de objeto se usa como un elemento de un objeto de colección, entonces este objeto debe tener su propio diseño equals () y hashCode (), y debe cumplir con los varios en principio.
En resumen, las cosas a tener en cuenta son:

Dos objetos con
igual a igual , hashCode debe ser igual Dos objetos con método de igual a desigual , hashCode puede ser igual a
0x1 Preguntas de entrevistas frecuentes

  1. ¿Has visto el código fuente de String? ¿Por qué utilizar la modificación final?
    La cadena de clase final pública
    implementa java.io.Serializable, Comparable, CharSequence {}
    Explicación principal:

1. Para lograr una piscina de cuerdas

2. Para la seguridad de los hilos

3. Para lograr la inmutabilidad de cadenas, se puede crear HashCode

La cadena modificada final representa la no heredabilidad de la cadena, y el carácter modificado final [] representa la inmutabilidad de los datos almacenados. Pero: aunque final representa inmutabilidad, pero solo la dirección de referencia es inmutable, no significa que la matriz en sí no cambiará.
Final también puede cambiar la matriz en sí. En este momento, private también es útil, porque los dos garantizan la inmutabilidad de String.
Entonces, ¿por qué asegurarse de que String sea inmutable, porque solo cuando la cadena es inmutable, el grupo de cadenas se puede realizar? La implementación del grupo de cadenas puede ahorrar mucho espacio en el montón en tiempo de ejecución, porque diferentes variables de cadena apuntan a la misma cadena en el grupo. Pero si la cadena es variable, entonces String.intern () no se implementará, porque en este caso, si la variable cambia su valor, los valores de otras variables que apuntan a este valor también cambiarán.
Debido a que la cadena es inmutable, el HashCode se almacena en caché cuando se crea y no es necesario volver a calcularlo. Esto hace que la cadena sea muy adecuada como clave en el mapa, y la velocidad de procesamiento de la cadena es más rápida que la de otros objetos clave. Esto es que las claves en HashMap a menudo usan cadenas.
2. ¿Cuáles son los métodos de inicialización de
String ? La inicialización del tipo String se divide en dos tipos en Java:

Un tipo se inicializa envolviendo un carácter entre comillas dobles; el
otro tipo es para inicializar una instancia de String como un objeto ordinario a través de la palabra clave new.
El primero abre una constante en el grupo de constantes l y devuelve la referencia correspondiente, mientras que el segundo abre una constante en el montón y luego devuelve el objeto correspondiente. Por tanto, la referencia de los dos es definitivamente diferente:

public static void main (String ... args) { String s1 = "abcd"; String s2 = new String ("abcd"); System.out.println (s1 == s2); // false } Y las constantes en el grupo de constantes Se puede compartir para ahorrar memoria y tiempo de creación (este es también el motivo de la introducción del grupo constante), por ejemplo:




public static void main (String… args) { String s1 = "abcd"; String s2 = "abcd"; System.out.println (s1 == s2); // true } Combinando los dos, en realidad puedes responder a otro Una pregunta común de la entrevista:




public static void main (String ... args) { String s = new String ("abcd"); } ¿ Cuántos objetos crea esta oración?


En primer lugar, no hay duda de que "abcd" en sí mismo es un objeto, que se coloca en la reserva constante. Dado que aquí se usa la nueva palabra clave, el objeto obtenido por s debe crearse en el montón. Entonces, en realidad hay 2 objetos creados aquí.

Cabe señalar que si la cadena "abcd" ya existe en algún otro lugar antes de que se llame a esta función, entonces se ha creado en el grupo de constantes de antemano. En este momento, solo se creará un objeto aquí, es decir, el nuevo objeto String ("abcd") creado en el montón.

  1. ¿Es seguro el hilo de cadena?
    String es una clase inmutable. Una vez que se crea un objeto String, no podemos cambiar su valor. Por lo tanto, es seguro para subprocesos y se puede utilizar de forma segura en un entorno de subprocesos múltiples.

  2. ¿Por qué usamos a menudo String como clave cuando usamos HashMap?
    Debido a que una cadena es inmutable, cuando se crea una cadena, su código hash se almacena en caché y no es necesario volver a calcularlo. Debido a que la implementación interna de HashMap usa el código hash de la clave para determinar la ubicación de almacenamiento del valor, es más rápido que otros objetos. Es por eso que usualmente usamos String como el objeto HashMap.

  3. ¿Cuál es el método intern () de String?
    El método String.intern () puede agregar constantes al grupo de constantes durante el tiempo de ejecución. La forma en que funciona es:

Si hay una constante en el grupo de constantes que es exactamente igual al valor de esta cadena, el método intern () devuelve una referencia a la constante que existe en el grupo de constantes.
Si no hay una constante en el grupo de constantes que sea igual al valor de esta cadena, se crea una nueva constante en el grupo de constantes y el valor de esta cadena se asigna a la constante recién creada en el grupo de constantes. El método intern () devuelve una referencia a esta constante recién creada.
Ejemplo:

public static void main (String ... args) { String s1 = “abcd”; Cadena s2 = nueva Cadena ("abcd");

/**
 * s2.intern() will first search String constant pool,
 * of which the value is the same as s2.
 */
String s3 = s2.intern();
// As s1 comes from constant pool, and s3 is also comes from constant pool, they're same.
System.out.println(s1 == s3);
// As s2 comes from heap but s3 comes from constant pool, they're different.
System.out.println(s2 == s3); 

}

/ **

  • Salida:
  • cierto
  • falso
    * /
    Recordando la primera parte del principio, ¿por qué introducir la función intern ()? Esto se debe a que, aunque se asigna "abcd" en el grupo de constantes, una vez que se usa una nueva cadena ("abcd"), se creará un nuevo objeto con el valor abcd en el montón. Imagínese, si hay 100 oraciones de este tipo, ¿no es necesario crear 100 objetos del mismo valor en el montón? ! Esto da como resultado un funcionamiento ineficaz y una pérdida de espacio.

Por lo tanto, si se introduce intern (), irá directamente al grupo constante para encontrar si hay objetos String con el mismo valor, lo que ahorra mucho espacio y mejora la eficiencia operativa.

  1. Algunas preguntas de programación sobre el grupo de constantes (1)
    Cadena s1 = "ab";
    Cadena s2 = "abc";
    Cadena s3 = s1 + "c";

System.out.println (s3 == s2); // false no es igual, s1 es una variable, el valor no se puede determinar al compilar, el valor se creará en la memoria y s3 ​​está en la memoria del montón. s2 está en el grupo constante, por lo que no es igual.
System.out.println (s3.equals (s2)); // true compara los valores de dos objetos por el mismo valor.
Explicación del código anterior:

Cadena s1 = "abc"; Cadena s2 = "abc";

s1 se creará en el grupo constante, s2 primero verificará si hay alguno en el grupo constante, si es así, apúntelo, si no, cree uno en el grupo constante y apúntelo. Entonces, las dos comparaciones de s1 y s2 son iguales.

  1. Algunas preguntas de programación sobre el grupo de constantes (2)
    Cadena s1 = nueva Cadena ("Hola");
    Cadena s2 = nueva Cadena ("Hola"); La
    respuesta es 3 objetos.

Primero, la línea 1 es el objeto "hola" en el grupo de cadenas.

En segundo lugar, línea 1, una nueva cadena con el valor "hola" en la memoria del montón.

En tercer lugar, línea 2, una nueva cadena con "hola" en la memoria del montón. Aquí se reutilizan las cadenas del grupo de cadenas "hola".

  1. ¿Hablar de la diferencia entre String, StringBuffer y StringBuilder?
    String es una clase inmutable, siempre que operamos en String, siempre se crea una nueva cadena. Operar String consume muchos recursos, por lo que Java proporciona dos clases de herramientas para manipular String: StringBuffer y StringBuilder.
    StringBuffer y StringBuilder son clases mutables, StringBuffer es seguro para subprocesos, StringBuilder no es seguro para subprocesos. Por lo tanto, cuando varios subprocesos operan en la misma cadena, debemos elegir StringBuffer. Debido a que no hay necesidad de lidiar con subprocesos múltiples, StringBuilder es más eficiente que StringBuffer.
    Revisión de Amazon www.yisuping.com

Supongo que te gusta

Origin blog.csdn.net/weixin_45032957/article/details/108599271
Recomendado
Clasificación