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 2

Publicado no grupo Random-PT
Olá novamente a todos! Continuamos buscando respostas para mais de 250 perguntas de desenvolvedores Junior, Middle e Senior. As questões são bastante interessantes e eu mesmo gosto de analisá-las: nesses momentos é possível descobrir lacunas no conhecimento teórico, e nos lugares mais inesperados. Análise de perguntas e respostas da entrevista.  Parte 2 - 1A parte anterior pode ser encontrada neste artigo . Mas antes de começarmos, quero lembrar que:
  1. Vou pular as perguntas que se cruzam com esta série de artigos para não duplicar informações mais uma vez. Recomendo a leitura desses materiais, pois eles contêm as perguntas mais comuns (populares) das entrevistas do Java Core.
  2. As perguntas sobre DOU são apresentadas em ucraniano, mas terei tudo aqui em russo.
  3. As respostas poderiam ser descritas com mais detalhes, mas não o farei, pois a resposta a cada pergunta poderia ocupar um artigo inteiro. E eles não farão perguntas tão detalhadas em nenhuma entrevista.
Se necessário, deixarei links para um estudo mais aprofundado. Vamos voar!

11. Nomeie todos os métodos da classe Object

A classe Object possui 11 métodos:
  • Class<?> getClass() — obtendo a classe do objeto atual;
  • int hashCode() — obtendo o código hash do objeto atual;
  • boolean equals​(Object obj) - comparação do objeto atual com outro;
  • Object clone() - criando e retornando uma cópia do objeto atual;
  • String toString() — obtendo uma representação em string de um objeto;
  • void notify() - desperta um thread aguardando no monitor deste objeto (a seleção do thread é aleatória);
  • void notifyAll() - desperta todas as threads que aguardam no monitor deste objeto;
  • void wait() - alterna o thread atual para o modo de espera (congela-o) no monitor atual, funciona apenas em um bloco sincronizado até que algum notify ou notifyAll ative o thread;
  • void wait(long timeout) - também congela o thread atual no monitor atual (no atual sincronizado), mas com um timer para sair deste estado (ou novamente: até notify ou notifyAll acordar);
  • void wait(long timeout, int nanos) - método semelhante ao descrito acima, mas com temporizadores mais precisos para sair do congelamento;
  • void finalize() - antes de excluir este objeto, o coletor de lixo chama esse método (finalmente). É usado para limpar recursos ocupados.
Para utilizar corretamente os métodos hashCode , equals​ , clone , toString e finalize, eles devem ser redefinidos, levando em consideração a tarefa e as circunstâncias atuais.

12. Qual é a diferença entre try-with-resources e try-catch-finally ao lidar com recursos?

Normalmente, ao usar try-catch-finalmente, o bloco final era usado para fechar recursos. Java 7 introduziu um novo tipo de operador try-with-resources , um análogo de try-catch-finalmente para liberar recursos, mas mais compacto e legível. Vamos lembrar como é o try-catch-finally :
String text = "some text......";
BufferedWriter bufferedWriter = null;
try {
   bufferedWriter = new BufferedWriter(new FileWriter("someFileName"));
   bufferedWriter.write(text);
} catch (IOException e) {
   e.printStackTrace();
} finally {
   try {
       bufferedWriter.close();
   } catch (IOException e) {
       e.printStackTrace();
   }
}
Agora vamos reescrever esse código, mas usando try-with-resources :
String text = "some text......";
try(BufferedWriter bufferedWriter =new BufferedWriter(new FileWriter("someFileName"))) {
   bufferedWriter.write(text);
} catch (IOException e) {
   e.printStackTrace();
}
De alguma forma ficou mais fácil, você não acha? Além da simplificação, existem alguns pontos:
  1. No try-with-resources , os recursos declarados entre parênteses (que serão fechados) devem implementar a interface AutoCloseable e seu único método, close() .

    O método close é executado em um bloco finalmente implícito , caso contrário, como o programa entenderá exatamente como fechar um determinado recurso?

    Mas, provavelmente, você raramente escreverá suas próprias implementações de recursos e seus métodos de fechamento.

  2. Sequência de execução do bloco:

    1. tente bloquear .
    2. Finalmente implícito .
    3. Um bloco catch que captura exceções nas etapas anteriores.
    4. Finalmente explícito .

    Via de regra, as exceções que aparecem mais abaixo na lista interrompem aquelas que aparecem mais acima.

Imagine uma situação em que ao usar try-catch-finalmente ocorre uma exceção no seu try . Assim, um bloco catch específico começa imediatamente a ser executado , no qual você escreve outra exceção (por exemplo, com uma mensagem que descreve o erro com mais detalhes) e deseja que o método lance essa exceção ainda mais. Em seguida vem a execução do bloco final , e uma exceção também é lançada nele. Mas isso é diferente. Qual dessas duas exceções esse método lançará? Exceção lançada pelo bloco final ! Mas também há um ponto com try-with-resources . Agora vamos examinar o comportamento do try-with-resources na mesma situação. Obtemos uma exceção no bloco try quando tentamos fechar recursos no método close() , ou seja, no finalmente implícito . Qual dessas exceções será capturada ? Aquele que foi lançado pelo bloco try ! Uma exceção de um finalmente implícito (do método close() ) será ignorada. Esse ignorar também é chamado de supressão de exceção.

13. O que são operações bit a bit?

Operações bit a bit são operações em cadeias de bits que incluem operações lógicas e mudanças bit a bit. Operações lógicas:
  • AND bit a bit - compara valores de bits, e no processo, qualquer bit definido como 0 (falso) define o bit correspondente no resultado como 0. Ou seja, se em ambos os valores sendo comparados o bit era 1 (verdadeiro), o o resultado também será 1.

    Denotado como - AND , &

    Exemplo: 10111101 e 01100111 = 00100101

  • OR bit a bit é a operação inversa da anterior. Qualquer bit definido como 1 define um bit semelhante no resultado como 1. E, consequentemente, se o bit for 0 em ambos os valores comparados, o bit resultante também será 0.

    Denotado como - OR , |

    Exemplo: 10100101 | 01100011 = 11100111

  • NOT bit a bit - aplicado a um valor, inverte (inverte) os bits. Ou seja, aqueles bits que eram 1 se tornarão 0; e aqueles que eram 0 se tornarão 1.

    Denotado como - NOT , ~

    Exemplo: ~10100101 = 01011010

  • OR exclusivo bit a bit - compara os valores dos bits, e se em ambos os valores o bit for igual a 1, então o resultado será 0, e se em ambos os valores o bit for 0, o resultado será 0. Ou seja, para que o resultado seja igual a 1, apenas um dos bits deve ser igual a 1, e o segundo deve ser igual a 0.

    Denotado como - XOR , ^

    Exemplo: 10100101 ^ 01100011 = 11000110

Deslocamentos bit a bit - >> ou << desloca os bits de um valor na direção especificada, pelo número especificado. As vagas vagas são preenchidas com zeros. Por exemplo:
  1. 01100011 >> 4 = 00000110
  2. 01100011 << 3 = 00011000
Há também uma exceção ao deslocar para a direita um número negativo. Como você lembra, o primeiro bit é responsável pelo sinal e, se esse bit for igual a 1, o número é negativo. Se mover um número negativo, as posições vagas não serão mais preenchidas com zeros, mas sim com uns, pois é necessário manter o bit de sinal. Por exemplo: 10100010 >> 2 = 11101000 Ao mesmo tempo, em Java existe um operador adicional de deslocamento para a direita sem sinal >>> Este operador é análogo de >>, ao deslocar, as posições vagas são preenchidas com 0, independentemente de o número é negativo ou positivo. Por exemplo: 10100010 >>> 2 = 00101000 Leia mais sobre operações bit a bit aqui . Análise de perguntas e respostas da entrevista.  Parte 2 - 2Como exemplos do uso de mudanças bit a bit em Java, você pode citar o método hash() de um HashMap, que é usado para determinar um código hash interno especial para uma chave: Análise de perguntas e respostas da entrevista.  Parte 2 - 3Este método permite distribuir uniformemente os dados em um HashMap para minimizar o número de colisões.

14. Quais classes imutáveis ​​padrão são objetos em Java?

Imutável é um objeto que não permite que seus parâmetros originais sejam alterados. Pode ter métodos que retornem novos objetos de um determinado tipo, com parâmetros que você deseja alterar. Alguns objetos imutáveis ​​padrão:
  • De longe, o objeto imutável mais famoso em Java é String;
  • instâncias de classes wrapper que agrupam tipos padrão: Boolean, Character, Byte, Short, Integer, Long, Double, Float;
  • objetos que normalmente são usados ​​para números especialmente GRANDES - BigInteger e BigDecimal;
  • um objeto que é uma unidade em stacktraces (por exemplo, em um stacktrace de exceção) StackTraceElement;
  • objeto da classe File - pode alterar arquivos, mas ao mesmo tempo é imutável;
  • UUID – que é frequentemente usado como um ID exclusivo para elementos;
  • todos os objetos de classe do pacote java.time;
  • Localidade - usada para definir uma região geográfica, política ou cultural.

15. Quais são as vantagens de um objeto imutável sobre objetos regulares?

  1. Esses objetos são seguros quando usados ​​em um ambiente multithread . Ao usá-los, você não precisa se preocupar com a perda de dados devido a condições de corrida de thread. Ao contrário de trabalhar com objetos comuns: neste caso, você terá que pensar com muito cuidado e elaborar os mecanismos de utilização do objeto em um ambiente paralelo.
  2. Objetos imutáveis ​​são boas chaves em um mapa, porque se você usar um objeto mutável e então o objeto mudar seu estado, pode ficar confuso ao usar um HashMap: o objeto ainda estará presente, e se você usar containsKey() ele pode não ser encontrado.
  3. Objetos imutáveis ​​são ótimos para armazenar dados imutáveis ​​(constantes) que nunca devem ser alterados enquanto o programa está em execução.
  4. “Atomicidade até a falha” - se um objeto imutável lançar uma exceção, ele ainda não permanecerá em um estado indesejado (quebrado).
  5. Essas classes são fáceis de testar.
  6. Mecanismos adicionais, como construtor de cópia e implementação de clone, não são necessários.

Perguntas sobre POO

Análise de perguntas e respostas da entrevista.  Parte 2 - 4

16. Quais são as vantagens da OOP em geral e em comparação com a programação processual?

Então, as vantagens do OOP:
  1. Aplicações complexas são mais fáceis de escrever do que programação processual, já que tudo é dividido em pequenos módulos – objetos que interagem entre si – e como resultado, a programação se resume a relacionamentos entre objetos.
  2. Aplicativos escritos usando OOP são muito mais fáceis de modificar (desde que os conceitos de design sejam seguidos).
  3. Como os dados e operações nele contidos formam uma única entidade, eles não ficam espalhados por toda a aplicação (o que geralmente acontece com a programação processual).
  4. O encapsulamento de informações protege os dados mais críticos do usuário.
  5. É possível reutilizar o mesmo código com dados diferentes, pois as classes permitem criar muitos objetos, cada um com seus próprios valores de atributos.
  6. A herança e o polimorfismo também permitem reutilizar e estender o código existente (em vez de duplicar funcionalidades semelhantes).
  7. Extensibilidade de aplicação mais fácil do que com uma abordagem processual.
  8. A abordagem OOP torna possível abstrair os detalhes da implementação.

17. Conte-nos quais são as deficiências que existem na OOP

Infelizmente, eles também estão presentes:
  1. OOP requer muito conhecimento teórico que precisa ser dominado antes que você possa escrever qualquer coisa.Análise de perguntas e respostas da entrevista.  Parte 2 - 5
  2. As ideias de OOP não são tão fáceis de entender e aplicar na prática (você precisa ser um pouco filósofo de coração).
  3. Ao usar OOP, o desempenho do software é ligeiramente reduzido devido à organização mais complexa do sistema.
  4. A abordagem OOP requer mais memória, pois tudo consiste em classes, interfaces, métodos, que ocupam muito mais memória do que variáveis ​​comuns.
  5. O tempo necessário para a análise inicial é maior que para a processual.

18. O que é polimorfismo estático e dinâmico

O polimorfismo permite que objetos se comportem de maneira diferente para a mesma classe ou interface. Existem dois tipos de polimorfismo, também conhecidos como ligação precoce e ligação tardia . Polimorfismo estático ou ligação anterior:
  • ocorre em tempo de compilação (no início do ciclo de vida do programa);
  • decide qual método executar em tempo de compilação;
  • A sobrecarga de método é um exemplo de polimorfismo estático;
  • a ligação antecipada inclui métodos privados, estáticos e terminais;
  • a herança não está envolvida na vinculação antecipada;
  • O polimorfismo estático não envolve objetos específicos, mas sim informações sobre a classe, cujo tipo é representado à esquerda do nome da variável.
Polimorfismo dinâmico ou ligação tardia:
  • ocorre em tempo de execução (enquanto o programa está em execução);
  • o polimorfismo dinâmico decide qual implementação específica um método terá em tempo de execução;
  • a substituição de método é um exemplo de polimorfismo dinâmico;
  • ligação tardia é a atribuição de um objeto específico, uma referência de seu tipo ou sua superclasse;
  • a herança está associada ao polimorfismo dinâmico.
Você pode ler mais sobre as diferenças entre vinculação antecipada e tardia neste artigo .

19. Defina o princípio da abstração em OOP

Abstração em OOP é uma forma de destacar um conjunto de características significativas de um objeto, excluindo detalhes sem importância. Ou seja, ao projetar um programa com abordagem OOP, você foca nos modelos em geral, sem se aprofundar nos detalhes de sua implementação. Em Java, as interfaces são responsáveis ​​pela abstração . Por exemplo, você tem uma máquina e esta será a interface. E várias interações com ele - por exemplo, ligar o motor, usar a caixa de câmbio - são funções que usamos sem entrar em detalhes de implementação. Afinal, no momento em que você está dirigindo um carro, você não pensa exatamente como a caixa de câmbio cumpre sua função, ou como a chave dá partida no motor, ou como exatamente o volante gira as rodas. E mesmo que a implementação de uma dessas funcionalidades seja substituída (por exemplo, o mecanismo), você pode não perceber. Isso não importa para você: você não entra em detalhes da implementação. É importante para você que a ação seja executada. Na verdade, isso é uma abstração dos detalhes da implementação. É aqui que vamos parar hoje: para continuar!Análise de perguntas e respostas da entrevista.  Parte 2 - 6
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION