JavaRush /Blog Java /Random-ES /Análisis de preguntas y respuestas de entrevistas para de...

Análisis de preguntas y respuestas de entrevistas para desarrollador Java. parte 10

Publicado en el grupo Random-ES
¡Hola! ¿Cuántas horas se necesitan para convertirse en un maestro en algo? A menudo he escuchado algo como: "Para convertirte en un maestro en cualquier cosa, necesitas dedicar 10.000 horas". Una cifra aterradora, ¿no? Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 10 - 1Sin embargo, me pregunto si esto es cierto. Y constantemente trato de calcular cuántas horas he invertido ya en dominar el arte de la programación. Y cuando supere esas preciadas 10.000 horas y me convierta en un maestro, ¿sentiré esta diferencia? ¿O ya los he pasado hace mucho tiempo sin darme cuenta? De una forma u otra, para convertirse en programador no es necesario invertir tanto tiempo. Lo principal es utilizarlo sabiamente. Su objetivo principal es aprobar la entrevista. Y en las entrevistas para recién llegados lo primero que preguntan es teoría, por eso hay que ser fuerte en ella. En realidad, al prepararse para la entrevista, su tarea es descubrir todas sus lagunas en la teoría básica de un desarrollador de Java y cubrirlas con conocimientos. Y hoy te ayudaré en este asunto, porque estoy aquí para seguir analizando las preguntas más populares. Así que ¡continuemos!

89. ¿En qué se diferencia ArrayList de LinkedList?

Esta es una de las preguntas más populares junto con la pregunta sobre la estructura interna de HashMap . Ninguna entrevista está completa sin él y, por lo tanto, la respuesta debería "rebotar en tus dientes". Además de lo obvio (diferentes nombres), se diferencian en su estructura interna. Anteriormente, examinamos la estructura interna de ArrayList y LinkedList , por lo que no entraré en detalles de su implementación. Permítanme recordarles que ArrayList se implementa en base a una matriz interna, que aumenta según sea necesario según la fórmula:
<размерТекущегоМассива> * 3 / 2  + 1
Al mismo tiempo, LinkedList se implementa en base a una lista interna doblemente enlazada, es decir, cada elemento tiene un enlace al anterior y al siguiente, excluyendo los valores que son el principio/final de la lista. A la gente le gusta hacer esta pregunta en el formato: "¿Cuál es mejor: ArrayList o LinkedList ?", con la esperanza de captarlo. Después de todo, si señala una de ellas como respuesta, será la respuesta incorrecta. Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 10 - 2En su lugar, debe aclarar de qué situación específica está hablando: acceso al índice o inserción en el medio de una lista. Dependiendo de la respuesta, podrás explicar tu elección. Anteriormente describí cómo funcionan ArrayList y LinkedList en una situación u otra. Resumamos esto colocándolos en la misma página para comparar: Agregar un elemento (agregar)
  1. Agregar un nuevo elemento sin especificar un índice como ubicación se producirá automáticamente al final de ambas listas. En una LinkedList, el nuevo elemento se convertirá en la nueva cola (solo se reescribe el par de enlaces: complejidad algorítmica O(1) ).

    В ArrayList будет добавлен новый элемент в последнюю пустую ячейку массива — O(1).

  2. Добавление elemento по индексу Cómo правило подразумевает вставку примерно в середину списка. В LinkedList сперва будет вестись поиск нужного места с помощью перебора элементов с “хвоста” и “головы” — O(n/2), а после — вставка значения путем переопределения ссылок элементов, между которыми вставляется новый — O(1). Суммарная алгоритмическая сложность данного действия будет O(n/2).

    ArrayList в данной ситуации по индексу находит элемент — O(1), и все элементы справа (включая элемент, который уже хранится по данному индексу) двигаются на одну единицу вправо (при этом возможно понадобится создание нового списка и копирование элементов в него) — O(n/2). Суммарная сложность — O(n/2).

  3. Добавление elemento в начало списка в LinkedList будет ситуация схожая с добавлением в конец: новый элемент станет новой “головой” — O(1), в то же время когда ArrayList-у нужно будет двигать все элементы вправо — O(n).

En pocas palabras: en LinkedList, la complejidad algorítmica variará de O(1) a O(n/2) . Es decir, cuanto más cerca esté la inserción del final o del principio de la lista, más rápida será. Al mismo tiempo, para ArrayList varía de O(1) a O(n) : cuanto más cerca esté la inserción del final de la lista, más rápida será. Establecer un elemento (conjunto) Esta operación escribe un elemento en la posición especificada en la lista, sobrescribiendo el anterior, si lo hubiera. En LinkedList, esta operación será similar a agregar, porque La mayor dificultad aquí es encontrar el elemento. La reescritura de un elemento se realizará reescribiendo un par de enlaces, por lo que aquí también la complejidad algorítmica variará de O(1) a O(n/2) dependiendo de la distancia de la posición desde el final o el principio de la lista. En ese momento, la celda requerida se encontrará en ArrayList para esta operación de índice y se escribirá en ella un nuevo elemento. La búsqueda de índice, como esta operación, tiene una complejidad algorítmica de O(1) . Tomar un elemento por índice (obtener) En LinkedList, tomar un elemento se producirá según el mismo principio que buscar otras operaciones, dependiendo de la distancia desde el final o el principio, es decir. de O(1) a O(n/2) . En ArrayList , como dije antes, encontrar un elemento en una matriz por índice tiene una complejidad O(1) . Eliminar un elemento por índice (eliminar) Para LinkedList, su principio de funcionamiento también funciona aquí: primero se encuentra el elemento y luego se sobrescriben los enlaces: los vecinos del elemento comienzan a referirse entre sí, perdiendo referencias a este elemento, lo que Posteriormente será eliminado por el recolector de basura. Es decir, la complejidad algorítmica sigue siendo la misma: de O(1) a O(n/2) . Para ArrayList , esta operación es más similar a la operación de agregar un nuevo elemento (agregar). Primero, se encuentra el elemento requerido: O(1) , luego se elimina y todos los elementos que estaban a la derecha se mueven una unidad hacia la izquierda para cerrar la brecha resultante. La operación de eliminación tendrá la misma complejidad algorítmica que la operación de adición: de O(1) a O(n) . Cuanto más cerca esté la eliminación del final de la lista, menos complejidad algorítmica tendrá. En realidad, estas fueron todas las operaciones principales. Permítanme recordarles: al comparar estas dos listas, es necesario aclarar de qué situación específica estamos hablando y luego poder responder sin ambigüedades a la pregunta planteada.

90. ¿En qué se diferencia ArrayList de HashSet?

Si ArrayList y LinkedList pudieran compararse en términos de operaciones, lo cual es mejor, entonces no es tan fácil comparar ArrayList con HashSet , porque son colecciones completamente diferentes. Puedes comparar un plato dulce con otro, pero funcionará con un plato de carne: son demasiado diferentes. Sin embargo, intentaré dar algunas diferencias entre ellos:
  • ArrayList implementa la interfaz List , mientras que HashSet implementa la interfaz Set ;

  • En ArrayList, el acceso es posible por índice de elemento: la operación de obtención tiene una complejidad algorítmica de O(1) , y en HashSet el elemento requerido solo se puede obtener por fuerza bruta, y esto es de O(1) a O(n). ;

  • ArrayList permite elementos duplicados. En un HashSet, todos los elementos son únicos: agregar un elemento a un HashSet cuyo análogo ya está presente en la colección no funcionará (los duplicados se verifican usando el código hash, de ahí el nombre de esta colección);

  • ArrayList se implementa usando una matriz interna y HashSet se implementa usando un HashMap interno ;

  • Un ArrayList mantiene el orden de inserción de los elementos, mientras que un HashSet es un conjunto desordenado y no mantiene el orden de los elementos;

  • ArrayList permite cualquier número de valores vacíos (nulo), solo se puede insertar un valor nulo en un HashSet (después de todo, la unicidad de los elementos).

91. ¿Por qué existe tanta variedad de implementaciones de matrices dinámicas en Java?

Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 10 - 3Bueno, esto es más una cuestión filosófica. Bueno, ¿por qué se les ocurren tantas tecnologías nuevas y diferentes? Por comodidad. En realidad, ocurre lo mismo con una gran cantidad de implementaciones de matrices dinámicas. Ninguno de ellos puede considerarse el mejor o el ideal. Cada uno tiene una ventaja en alguna situación específica. Y nuestra tarea es conocer sus diferencias, sus fortalezas/debilidades: para poder utilizar el más adecuado en la situación adecuada.

92. ¿Por qué existe tanta variedad de implementaciones de almacenamiento de valores clave en Java?

Aquí la situación es la misma que con las implementaciones de matrices dinámicas. No hay nadie mejor: cada uno tiene fortalezas y debilidades. Y nosotros, por supuesto, debemos aprovechar al máximo nuestras fortalezas. Ejemplo: el paquete concurrente, que contiene muchas tecnologías multiproceso, tiene sus propias colecciones concurrentes . El mismo ConcurrentHashMap tiene una ventaja en la seguridad del trabajo multiproceso con datos en comparación con un HashMap normal , pero en un entorno sin multiproceso pierde velocidad. Bueno, las implementaciones, que no son las más sólidas en ninguna situación, poco a poco se van dejando de utilizar. Ejemplo: Hashtable , que originalmente estaba destinado a ser un HashMap seguro para subprocesos , pero ConcurrentHashMap lo superó en un entorno de subprocesos múltiples y, finalmente, Hashtable fue olvidado y ya no se usó.

93. ¿Cómo ordenar una colección de elementos?

Lo primero que hay que decir es que la clase de elemento de colección debe implementar la interfaz Comparable y su método compareTo . O necesita una clase que implemente Comaprator con su método comparador . Puedes leer más sobre ellos en este post . Ambos métodos especifican cómo se deben comparar los objetos de un tipo determinado. Al ordenar, esto es de vital importancia, porque es necesario comprender el principio mediante el cual se pueden comparar los elementos. La forma principal de hacer esto es implementar Comparable , implementado directamente en la clase que desea ordenar. Al mismo tiempo, el uso de Comparator es menos común. Digamos que estás usando una clase de alguna biblioteca que no tiene una implementación Comparable , pero necesitarás ordenarla de alguna manera. Sin poder cambiar el código de esta clase (excepto extendiéndolo), puedes escribir una implementación de Comparator , en la que indicas según qué principio quieres comparar objetos de esta clase. Y un ejemplo más. Digamos que necesitas diferentes principios para clasificar objetos del mismo tipo, por lo que escribes varios comparadores que usas en diferentes situaciones. Como regla general, muchas clases listas para usar ya implementan la interfaz Comparable , la misma String . En realidad, al usarlos, no tienes que preocuparte por cómo compararlos. Simplemente tómalos y úsalos. La primera y más obvia forma es utilizar una colección de tipo TreeSet o TreeMap , que almacena los elementos ya ordenados según el comparador de clases de elementos. Recuerde que TreeMap ordena claves, pero no valores. Si usa la implementación Comparator en lugar de Comparable , deberá pasar su objeto al constructor de la colección al momento de la creación:
TreeSet treeSet = new TreeSet(customComparator);
¿Pero qué pasa si tienes un tipo diferente de colección? ¿Cómo ordenarlo? En este caso, el segundo método de la clase de utilidad Colecciones es adecuado : el método sort() . Es estático, por lo que todo lo que necesitas es el nombre de la clase y un método al que se pasa la lista requerida. Por ejemplo:
Collections.sort(someList);
Si no está utilizando Comparable , sino una implementación de Comparator , debe pasarlo como segundo parámetro:
Collections.sort(someList, customComparator);
Como resultado, el orden interno de los elementos de la lista pasada cambiará: se ordenarán según el comparador de elementos. Observo que la lista de elementos transferida debe ser mutable, es decir mutable; de ​​lo contrario, el método no funcionará y se generará una excepción UnsupportedOperationException . Como tercera forma, puedes utilizar la operación Stream sort , que ordena los elementos de la colección si se utiliza la implementación Comparable :
someList = someList.stream().sorted().collect(Collectors.toList());
si comparador :
someList = someList.stream().sorted(customComparator).collect(Collectors.toList());
Puedes leer más sobre Stream en este artículo . El cuarto método consiste en implementar manualmente la clasificación, como la clasificación por burbujas o la clasificación por combinación .

Objeto de clase. Iguales y HashCode

94. Dé una breve descripción del objeto de clase en Java.

En la segunda parte del análisis ya hablamos de los métodos de la clase Object , y les recordaré que la clase Object es la progenitora de todas las clases en Java. Tiene 11 métodos que, en consecuencia, son heredados por todas las clases. Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 10 - 4Puede encontrar información sobre los 11 métodos en la segunda parte de la discusión.

95. ¿Para qué se utilizan Equals y HashCode en Java?

hashCode() es un método de la clase Object que heredan todas las clases. Su tarea es generar algún número que represente un objeto específico. Un ejemplo del uso de este método es su uso en un HashMap en un objeto clave para determinar aún más el código hash local, que determinará la celda de la matriz interna (depósito) en la que se almacenará el par. Hablamos en detalle sobre el trabajo de HashMap en la parte 9 del análisis , por lo que no nos detendremos demasiado en esto. Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 10 - 5Además, como regla general, este método se utiliza en el método equals() como una de sus principales herramientas para determinar la identidad de los objetos. equals() es un método de la clase Object cuyo trabajo es comparar objetos y determinar si son iguales o no. Este método se usa en todos los lugares donde necesitamos comparar objetos, porque la comparación habitual usando == no es adecuada para objetos, porque compara sólo enlaces a ellos.

96. ¿Cuéntanos sobre el contrato entre Equals y HashCode en Java?

Lo primero que diré es que para que los métodos equals() y hashCode() funcionen correctamente , es necesario anularlos correctamente. Después de esto deberán seguir las reglas:
  • los objetos idénticos para los cuales la comparación mediante iguales devuelve verdadero deben tener los mismos códigos hash ;
  • Es posible que los objetos con los mismos códigos hash no siempre sean iguales.
¡En este punto haremos una pausa hasta la siguiente parte del análisis!Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 10 - 6
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION