JavaRush /Blogue Java /Random-PT /Análise de perguntas e respostas de entrevistas para dese...

Análise de perguntas e respostas de entrevistas para desenvolvedor Java. Parte 11

Publicado no grupo Random-PT
Olá! Mesmo o navio mais rápido sem rumo simplesmente flutuará ao longo das ondas. Se você está lendo meu artigo agora, definitivamente tem um objetivo. O principal é não se perder, mas seguir sua linha até o fim - tornar-se um desenvolvedor Java. Hoje quero continuar minha análise de mais de 250 perguntas para desenvolvedores Java, que o ajudarão a cobrir algumas lacunas na teoria. Análise de perguntas e respostas de entrevistas para desenvolvedor Java.  Parte 11 - 1

97. As condições de redefinição do acordo são impostas na redefinição do Equals?

O método equals() substituído deve obedecer às seguintes condições (regras):
  • reflexividade - para qualquer valor x, uma expressão como x.equals(x) deve sempre retornar true (quando x != null ).

  • simetria - para quaisquer valores de x e y, uma expressão no formato x.equals(y) deve retornar true somente se y.equals(x) retornar true .

  • transitividade - para quaisquer valores de x , y e z , se x.equals(y) retornar true e y.equals(z) também retornar true , então x.equals(z) deverá retornar true .

  • consistência - para quaisquer valores de x e y, uma chamada repetida para x.equals(y) sempre retornará o valor da chamada anterior para este método, desde que os campos usados ​​para comparar os dois objetos não tenham mudado entre as chamadas .

  • comparação nula - para qualquer valor x, chamar x.equals(null) retornará false .

98. O que acontece se você não substituir Equals e HashCode?

Neste caso, hashCode() retornará um número gerado com base na localização da memória em que o objeto fornecido está armazenado. Ou seja, dois objetos com campos exatamente iguais receberão valores diferentes ao chamar um hashCode() não substituído (afinal, eles são armazenados em locais de memória diferentes). O equals() não substituído compara referências para ver se elas apontam para o mesmo objeto ou não. Ou seja, a comparação é feita através de == , e no caso de objetos com os mesmos campos retornará sempre false . True só será quando comparar referências ao mesmo objeto. Às vezes há lógica em não substituir esses métodos. Por exemplo, você deseja que todos os objetos de uma determinada classe sejam únicos e substituir esses métodos apenas prejudicará a lógica da exclusividade. O principal é compreender as nuances dos métodos substituídos e não substituídos e usar ambas as abordagens dependendo da situação.

99. Por que a simetria só é verdadeira se x.equals(y) retornar verdadeiro?

Uma pergunta um pouco estranha. Se o objeto A é igual ao objeto B, então o objeto B é igual ao objeto A. Se B não é igual ao objeto A, então como é possível o oposto? Esta é uma lógica simples. Análise de perguntas e respostas de entrevistas para desenvolvedor Java.  Parte 11 - 2

100. O que é colisão no HashCode? Como lidar com isso?

Uma colisão hashCode é uma situação em que dois objetos diferentes possuem o mesmo valor hashCode . Como isso é possível? O fato é que o hashcode é mapeado para o tipo Integer , que por sua vez possui um intervalo de -2147483648 a 2147483647, ou seja, aproximadamente 4 bilhões de inteiros diferentes. Essa gama é enorme, porém não é infinita. Portanto, situações são possíveis quando dois objetos completamente diferentes possuem o mesmo código hash. Isto é altamente improvável, mas possível. Uma função hash mal implementada também pode aumentar a frequência de códigos hash idênticos, o que retornará, por exemplo, números em um intervalo pequeno, o que aumentará a chance de colisões. Para combater uma colisão, é necessário ter uma boa implementação do método hashCode para que a dispersão dos valores seja máxima e a chance de repetição de valores seja mínima.

101. O que acontece se um elemento participante de um contrato HashCode alterar seu valor?

Se um elemento envolvido no cálculo do código hash for alterado, o código hash do próprio objeto será alterado (se a função hash for boa). Portanto, no HashMap é recomendado usar objetos imutáveis ​​(inalteráveis) como chave, pois seu estado interno (campos) não pode ser alterado após a criação. Conseqüentemente, seu código hash também não é convertido após a criação. Se você usar um objeto mutável como chave, ao alterar os campos desse objeto, seu código hash mudará e, como resultado, você poderá perder esse par no HashMap . Afinal, ele será armazenado no bucket do código hash original e, após alterá-lo, será pesquisado em outro bucket. Análise de perguntas e respostas de entrevistas para desenvolvedor Java.  Parte 11 - 3

102. Escreva métodos Equals e HashCode para a classe Student, que consiste em campos String name e 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;
 }
}
É igual a:
  • Primeiro, comparamos os links diretamente, porque se os links são para o mesmo objeto, qual o sentido de continuar a verificação? Tudo será verdade de qualquer maneira .

  • Verificando se há null e tipos de classe correspondentes, porque se um objeto é um argumento de null ou de outro tipo, isso significa que os objetos não são iguais - false .

  • Convertendo o objeto de argumento para um tipo (caso seja um objeto do tipo pai).

  • Comparação de um campo de classe primitiva (afinal, comparação via =! é suficiente para isso ), se o campo não for igual - false .

  • Verificando um campo não primitivo para null e equals (em String o método é substituído e será comparado corretamente), se ambos os campos forem null ou equals , a verificação termina e o método retorna true .

Código Hash:
  • Definir o valor do código hash inicial para a idade primitiva do objeto .

  • Multiplicar o código hash atual por 31 (para maior propagação) e adicionar a ele o código hash de um campo de string não primitivo (se não for nulo).

  • Retornando o resultado.

  • Como resultado dessa substituição do código hash, objetos com o mesmo nome e valores int sempre retornarão o mesmo valor.

103. Qual é a diferença entre usar if (obj instanceof Student) e if (getClass() == obj.getClass())?

Vejamos o que cada abordagem faz:
  • instanceof verifica se uma referência de objeto no lado esquerdo é uma instância de um tipo no lado direito ou algum subtipo dele.

  • getClass() == ... verifica a identidade do tipo.

Ou seja, se getClass() verificar a identidade completa de uma classe, então instanceof retornará true mesmo se o objeto for apenas um subtipo, o que pode nos dar mais flexibilidade ao usar ativamente o polimorfismo. Na verdade, ambas as abordagens são boas se você compreender as características de seu trabalho e aplicá-las nos lugares certos.

104. Dê uma breve descrição do método clone().

Clone() é um método da classe Object , cujo objetivo é criar e retornar um clone do objeto atual (uma cópia do objeto atual). Análise de perguntas e respostas de entrevistas para desenvolvedor Java.  Parte 11 - 4Para usá-lo, você precisa implementar a interface do marcador Cloneable :
Student implements Cloneable
E substitua o próprio método clone() :
@Override
protected Object clone() throws CloneNotSupportedException {
 return super.clone();
}
Afinal, na classe Object ele está protegido, ou seja, ficará visível apenas na própria classe Student , mas não será visível para as classes externas.

105. Qual a peculiaridade do método clone() trabalhar com os campos de um objeto do tipo referência?

Ao clonar objetos, apenas os valores primitivos e o valor das referências do objeto são copiados. Isso significa que se um objeto tiver um link para outro objeto em seu campo interno, então apenas esse link será clonado, mas esse outro objeto em si não será clonado. Na verdade, isso é o que chamam de clonagem de superfície. Bem, e se você precisar de uma clonagem completa com clonagem de todos os objetos aninhados? Como ter certeza de que não são cópias de links, mas clones completos de objetos com outras células de memória ocupadas no heap? Na verdade, tudo é bastante simples - para isso você também precisa substituir o método clone() em cada classe desses objetos internos e adicionar uma interface de marcador - Cloneable . Então não serão as referências aos objetos que serão copiadas, mas os próprios objetos, pois agora eles também têm a capacidade de se copiar.

Exceções

106. Qual é a diferença entre erro e exceção?

Tanto as exceções quanto os erros são subclasses da classe Throwable . No entanto, eles têm suas diferenças. O erro indica um problema que ocorre principalmente devido a recursos insuficientes do sistema. E nossa aplicação não deve detectar esse tipo de problema. Alguns dos exemplos de erros são falha do sistema e erro de falta de memória. Os erros ocorrem principalmente em tempo de execução, pois são de um tipo não verificado. Análise de perguntas e respostas de entrevistas para desenvolvedor Java.  Parte 11 - 5As exceções são problemas que podem ocorrer em tempo de execução e em tempo de compilação. Normalmente isso acontece em código escrito por desenvolvedores. Ou seja, as exceções são mais previsíveis e mais dependentes de nós como desenvolvedores. Ao mesmo tempo, os erros são mais aleatórios e independentes de nós, mas dependem de problemas com o próprio sistema no qual nosso aplicativo é executado.

107. Qual é a diferença entre verificado e não verificado, exceção, lançamento, lançamento.

Como falei anteriormente, uma exceção é um erro durante a execução do programa e durante a compilação que ocorreu no código escrito pelo desenvolvedor (devido a alguma situação anormal). Checked é um tipo de exceção que sempre deve ser tratada usando o mecanismo try-catch ou lançada nos métodos acima. Throws é usado no cabeçalho do método para indicar possíveis exceções lançadas pelo método. Ou seja, este é o mecanismo para “lançar” exceções nos métodos acima. Unchecked é um tipo de exceção que não precisa ser tratada e normalmente é menos previsível e menos provável de ocorrer. No entanto, eles também podem ser processados, se desejado. Throw é usado ao lançar uma exceção manualmente, por exemplo:
throw new Exception();

108. Qual é a hierarquia das exceções?

A hierarquia de exceções é muito grande e extensa, até mesmo extensa para contar tudo sobre ela aqui. Portanto, consideraremos apenas seus links principais: Análise de perguntas e respostas de entrevistas para desenvolvedor Java.  Parte 11 - 6Aqui, no topo da hierarquia, vemos a classe - Throwable - uma classe geral, ancestral da hierarquia de exceções, que por sua vez é dividida em:
  • Erro - erros críticos e não verificáveis.
  • Exceção - exceções verificadas.
A exceção é dividida em várias exceções de tempo de execução não verificadas e várias exceções verificadas.

109. O que é exceção marcada e não verificada?

Como eu disse antes:
  • Verificados - exceções que você deve tratar de alguma forma, ou seja, processá-las em um bloco try-catch ou “encaminhá-las” para o método acima. Para isso, na assinatura do método, após listar os argumentos do método, é necessário utilizar a palavra-chave trows <tipo de exceção> , que indica aos usuários do método que o método pode lançar essa exceção (algo como um aviso) e transfere o responsabilidade de lidar com a exceção aos usuários deste método.

  • Unchecked - exceções que não precisam ser tratadas, pois não são verificadas em tempo de compilação e, via de regra, são mais imprevisíveis. Ou seja, a principal diferença com o verificado é que para eles esses mecanismos de try-catch ou arremesso funcionam da mesma forma, mas não são obrigatórios.

101. Escreva um exemplo de interceptação e tratamento de uma exceção em um bloco try-catch de um método

try{                                                 // начало блока перехвата
 throw new Exception();                             // ручной бросок исключения
} catch (Exception e) {                              // данное исключение и его потомки будут перехватываться
 System.out.println("Упс, что-то пошло не так =("); // вывод некоторого исключения в консоль
}

102. Escreva um exemplo de como capturar e tratar uma exceção usando suas próprias exceções

Primeiro, vamos escrever nossa própria classe de exceção, que herda de Exception e sobrescreve seu construtor com uma mensagem de erro:
public class CustomException extends Exception {

 public CustomException(final String message) {
   super(message);
 }
}
Bem, então vamos lançá-lo manualmente e interceptá-lo como na pergunta anterior:
try{
 throw new CustomException("Упс, что-то пошло не так =(");
} catch (CustomException e) {
 System.out.println(e.getMessage());
}
E novamente, ao executá-lo, você obterá a seguinte saída no console:
Ops, algo deu errado =(
Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 11 - 7Você pode descobrir mais sobre as exceções aqui . Bem, isso é tudo por hoje! Vejo você na próxima parte!
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION