CodeGym /Blog Java /Random-ES /Explorando preguntas y respuestas de una entrevista de tr...
John Squirrels
Nivel 41
San Francisco

Explorando preguntas y respuestas de una entrevista de trabajo para un puesto de desarrollador de Java. parte 11

Publicado en el grupo Random-ES
¡Hola! Incluso el barco más rápido simplemente flotará sobre las olas si no tiene rumbo. Si estás leyendo este artículo ahora mismo, definitivamente tienes un objetivo. Lo principal es no desviarse del rumbo y, en cambio, hacer todo lo posible para convertirse en desarrollador de Java. Hoy quiero continuar mi revisión de preguntas para desarrolladores de Java para ayudar a llenar algunos de sus vacíos en teoría. Explorando preguntas y respuestas de una entrevista de trabajo para un puesto de desarrollador de Java.  Parte 11 - 1

97. ¿Se aplica alguna regla al anular iguales ()?

Al anular el método equals(), debes cumplir con las siguientes reglas:
  • reflexividad : para cualquier valor x , x.equals(x) siempre debe devolver verdadero (donde x != null ).

  • simetría : para cualquier valor x e y , x.equals(y) debe devolver verdadero solo si y.equals(x) devuelve verdadero .

  • transitividad : para cualquier valor x , y y z , si x.equals(y) devuelve verdadero y y.equals(z) también devuelve verdadero , entonces x.equals(z) debe devolver verdadero .

  • coherencia : para cualquier valor x e y , llamar repetidamente a x.equals(y) siempre devolverá el mismo valor siempre que los campos utilizados para comparar los dos objetos no hayan cambiado entre cada llamada.

  • comparación nula : para cualquier valor x , llamar a x.equals(null) debe devolver false .

98. ¿Qué sucede si no anulas equals() y hashCode()?

En este caso, hashCode() devolverá un número generado en función de la dirección de la celda de memoria donde está almacenado el objeto. En otras palabras, cuando se llama al método hashCode() original en dos objetos con exactamente los mismos campos, el resultado será diferente (porque están almacenados en diferentes ubicaciones de memoria). El método original equals() compara referencias, es decir, indica si las referencias apuntan al mismo objeto. En otras palabras, la comparación utiliza el operador == y siempre devolverá falso para diferentes objetos, incluso cuando sus campos sean idénticos. true solo se devuelve cuando se comparan referencias al mismo objeto. A veces tiene sentido no anular estos métodos. Por ejemplo, desea que todos los objetos de una determinada clase sean únicos; anular estos métodos sólo podría arruinar la garantía existente de códigos hash únicos. Lo importante es comprender los matices de estos métodos, ya sea que se anulen o no, y utilizar el enfoque que requiera la situación.

99. ¿Por qué se cumple el requisito de simetría sólo si x.equals(y) devuelve verdadero?

Esta pregunta es un poco extraña. Si el objeto A es igual al objeto B, entonces el objeto B es igual al objeto A. Si B no es igual al objeto A, ¿cómo podría ser posible lo contrario? Esto es sentido común.

100. ¿Qué es una colisión de HashCode? ¿Cómo lo afrontas?

Una colisión de HashCode ocurre cuando dos objetos diferentes tienen el mismo HashCode . ¿Cómo es eso posible? Bueno, el código hash se asigna a un número entero, que tiene un rango de -2147483648 a 2147483647. Es decir, puede ser uno de aproximadamente 4 mil millones de números enteros diferentes. Este rango es enorme pero no infinito. Eso significa que hay situaciones en las que dos objetos completamente diferentes pueden tener el mismo código hash. Es muy poco probable, pero es posible. Una función hash mal implementada puede hacer que códigos hash idénticos sean más frecuentes al devolver números en un rango pequeño, aumentando así la posibilidad de colisiones. Para reducir las colisiones, es necesario tener una buena implementación del método HashCode que distribuya uniformemente los valores y minimice la posibilidad de que se repitan valores.

101. ¿Qué sucede si cambia el valor de un elemento que participa en el contrato hashCode?

Si un elemento involucrado en el cálculo de un código hash cambia, entonces el código hash del objeto debería cambiar (si la función hash es buena). Es por eso que debes usar objetos inmutables como claves en un HashMap , ya que su estado interno (campos) no se puede cambiar después de la creación. Y se deduce que su código hash cambia después de la creación. Si usa un objeto mutable como clave, cuando los campos del objeto cambien, su código hash cambiará y podría perder el par clave-valor correspondiente en HashMap . Después de todo, se almacenará en el depósito asociado con el código hash original, pero después de que el objeto cambie, lo buscará en un depósito diferente.

102. Escriba los métodos equals() y hashCode() para una clase Student que tenga campos String name y int age.

public class Student {
int age;
String name;

 @Override
 public boolean equals(final Object o) {
   if (this == o) {
     return true;
   }
   if (o == null || this.getClass() != o.getClass()) {
     return false;
   }

   final Student student = (Student) o;

   if (this.age != student.age) {
     return false;
   }
   return this.name != null ? this.name.equals(student.name) : student.name == null;
 }

 @Override
 public int hashCode() {
   int result = this.age;
   result = 31 * result + (this.name != null ? this.name.hashCode() : 0);
   return result;
 }
}
es igual():
  • Primero, comparamos las referencias directamente, porque si las referencias apuntan al mismo objeto, ¿qué sentido tiene seguir verificando la igualdad? Ya sabemos que el resultado será cierto .

  • Comprobamos si hay nulos y si los tipos de clase son los mismos porque si el parámetro es nulo o de otro tipo, entonces los objetos no pueden ser iguales y el resultado debe ser falso .

  • Emitimos el parámetro al mismo tipo (después de todo, ¿qué pasa si es un objeto del tipo principal)?

  • Comparamos los campos primitivos (una comparación usando =! será suficiente). Si no son iguales, devolvemos falso .

  • Comprobamos el campo no primitivo para ver si es nulo y usando el método igual (la clase String anula el método, por lo que realizará la comparación correctamente). Si ambos campos son nulos o igual devuelve verdadero , dejamos de verificar y el método devuelve verdadero .

código hash() :
  • Establecemos el valor inicial del código hash igual al valor del campo de edad del objeto .

  • Multiplicamos el código hash actual por 31 (para una mayor dispersión de valores) y luego agregamos el código hash del campo Cadena no primitivo (si no es nulo).

  • Devolvemos el resultado.

  • Anular el método de esta manera significa que los objetos con el mismo nombre y valores int siempre devolverán el mismo código hash.

103. ¿Cuál es la diferencia entre usar "if (obj instancia de Estudiante)" y "if (getClass() == obj.getClass())"?

Echemos un vistazo a lo que hace cada expresión:
  • instancia de comprueba si la referencia del objeto en el lado izquierdo es una instancia del tipo en el lado derecho o uno de sus subtipos.

  • "getClass() == ..." comprueba si los tipos son iguales.

En otras palabras, getClass() devuelve la identidad específica de la clase, pero instanciade devuelve verdadero incluso si el objeto es sólo un subtipo, lo que puede darnos más flexibilidad al usar polimorfismo. Ambos enfoques son prometedores si se comprende con precisión cómo funcionan y se aplican en los lugares correctos.

104. Dé una breve descripción del método clone().

El método clone() pertenece a la clase Objeto . Su propósito es crear y devolver un clon (copia) del objeto actual. Explorando preguntas y respuestas de una entrevista de trabajo para un puesto de desarrollador de Java.  Parte 11 - 2Para utilizar este método, debe implementar la interfaz del marcador clonable :
Student implements Cloneable
Y anule el método clone() en sí:
@Override
protected Object clone() throws CloneNotSupportedException {
 return super.clone();
}
Después de todo, está protegido en la clase Objeto , es decir, sólo será visible dentro de la clase Estudiante y no visible para clases externas.

105. ¿Qué consideraciones especiales debes tener en cuenta con respecto al método clone() y las variables de referencia en un objeto?

Cuando se clonan objetos, solo se copian los valores primitivos y el valor de las referencias del objeto. Esto significa que si un objeto tiene un campo que hace referencia a otro objeto, entonces solo se clonará la referencia; este otro objeto al que se hace referencia no se clonará. Esto es lo que se llama copia superficial. Entonces, ¿qué pasa si necesita una copia completa, donde se clonen todos los objetos anidados? ¿Cómo se asegura de que no sean meras copias de referencias, sino copias completas de objetos distintos que ocupan distintas direcciones de memoria en el montón? En realidad, todo es bastante simple: para cada clase a la que se hace referencia internamente, debe anular el método clone() y agregar la interfaz de marcador Cloneable . Una vez que haga esto, la operación de clonación no copiará las referencias a objetos existentes, sino que copiará los objetos a los que se hace referencia, ya que ahora también tienen la capacidad de copiarse a sí mismos.

Excepciones

106. ¿Cuál es la diferencia entre un error y una excepción?

Las excepciones, así como los errores, son subclases de Throwable . Sin embargo, tienen sus diferencias. El error indica un problema que ocurre principalmente por falta de recursos del sistema. Y nuestra aplicación no debería ver este tipo de problemas. Ejemplos de estos errores incluyen un fallo del sistema y un error de falta de memoria. Los errores ocurren principalmente en tiempo de ejecución, ya que no están verificados. Explorando preguntas y respuestas de una entrevista de trabajo para un puesto de desarrollador de Java.  Parte 11 - 3Las excepciones son problemas que pueden ocurrir en tiempo de ejecución y en tiempo de compilación. Estos problemas suelen surgir en el código que escribimos como desarrolladores. Eso significa que estas excepciones son más predecibles y más dependientes de nosotros. Por el contrario, los errores son más aleatorios y más independientes de nosotros. En cambio, dependen de problemas en el sistema en el que se ejecuta nuestra aplicación.

107. ¿Cuál es la diferencia entre marcado, no marcado, excepción, lanzamiento y lanzamiento?

Como dije antes, una excepción es un error de tiempo de ejecución o de compilación que ocurre en el código escrito por el desarrollador (debido a alguna situación anormal). Se marca lo que llamamos excepciones que un método siempre debe manejar utilizando el mecanismo try-catch o volviendo a lanzar al método de llamada. La palabra clave throws se utiliza en el encabezado de un método para indicar las excepciones que el método podría generar. En otras palabras, nos proporciona un mecanismo para lanzar excepciones al método de llamada. No es necesario manejar las excepciones no marcadas . Suelen ser menos predecibles y menos probables. Dicho esto, puedes manejarlos si quieres. Usamos throw cuando lanzamos manualmente una excepción, por ejemplo:
throw new Exception();

108. ¿Qué es la jerarquía de excepciones?

La jerarquía de excepciones es muy extensa. Hay demasiado para describir adecuadamente aquí. Entonces, en lugar de eso, solo consideraremos sus ramas clave: Explorando preguntas y respuestas de una entrevista de trabajo para un puesto de desarrollador de Java.  Parte 11 - 4 aquí, en la parte superior de la jerarquía, vemos la clase Throwable , que es el antepasado general de la jerarquía de excepciones y, a su vez, se divide en:
  • Errores : problemas críticos y no controlados.
  • Excepciones : excepciones que se pueden comprobar.
Las excepciones se dividen en varias excepciones de tiempo de ejecución no comprobadas y varias excepciones comprobadas.

109. ¿Qué son las excepciones marcadas y no marcadas?

Como dije antes:
  • Las excepciones marcadas son excepciones que debes manejar de alguna manera. Es decir, debes manejarlos en un bloque try-catch o lanzarlos al método anterior. Para hacer esto, después de enumerar los argumentos del método en la firma del método, use throws <tipo de excepción> para indicar que el método puede generar esa excepción. Esto es algo así como una advertencia, avisando al método de llamada que debe asumir la responsabilidad de manejar esa excepción.

  • No es necesario gestionar las excepciones no comprobadas , ya que no se comprueban en el momento de la compilación y suelen ser más impredecibles. Su principal diferencia con las excepciones marcadas es que manejarlas mediante el uso de un bloque try-catch o volviendo a lanzarlas es opcional y no obligatorio.

101. Escriba un ejemplo en el que utilice un bloque try-catch para detectar y manejar una excepción.

try{                                                 // Start of the try-catch block
 throw new Exception();                             // Manually throw an exception
} catch (Exception e) {                              // Exceptions of this type and its subtypes will be caught
 System.out.println("Oops! Something went wrong =("); // Display the exception
}

102. Escriba un ejemplo en el que detecte y maneje sus propias excepciones personalizadas.

Primero, escribamos nuestra propia clase de excepción que herede Exception y anulemos su constructor que toma un mensaje de error como argumento:
public class CustomException extends Exception {

 public CustomException(final String message) {
   super(message);
 }
}
A continuación, lanzaremos uno manualmente y lo capturaremos tal como lo hicimos en el ejemplo de la pregunta anterior:
try{
 throw new CustomException("Oops! Something went wrong =(");
} catch (CustomException e) {
 System.out.println(e.getMessage());
}
Una vez más, cuando ejecutamos nuestro código, obtenemos el siguiente resultado:
¡Ups! Algo salió mal =(
Explorando preguntas y respuestas de una entrevista de trabajo para un puesto de desarrollador de Java.  Parte 11 - 5Bueno, ¡eso es todo por hoy! ¡Nos vemos en la siguiente parte!
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION