CodeGym /Blogue Java /Random-PT /Explorando perguntas e respostas de uma entrevista de emp...
John Squirrels
Nível 41
San Francisco

Explorando perguntas e respostas de uma entrevista de emprego para um cargo de desenvolvedor Java. Parte 2

Publicado no grupo Random-PT
Olá novamente a todos! Continuamos buscando respostas para perguntas de desenvolvedores Java juniores, médios e seniores. As perguntas são super interessantes. Pessoalmente gosto de analisá-los, porque me ajuda a encontrar lacunas no meu conhecimento teórico, e às vezes nos lugares mais inesperados. Explorando perguntas e respostas de uma entrevista de emprego para um cargo de desenvolvedor Java.  Parte 2 - 1A parte anterior pode ser encontrada neste artigo . Mas antes de começarmos, quero lembrar que:
  1. Irei pular as questões que se sobrepõem a esta série de artigos para não duplicar informações desnecessariamente. Eu recomendo a leitura desses artigos, pois eles cobrem as perguntas mais comuns (populares) das entrevistas do Java Core.
  2. Eu poderia descrever as respostas com mais detalhes, mas não o farei, porque cada resposta poderia se arrastar por todo o artigo. E ninguém vai pedir esse nível de detalhe em qualquer entrevista de emprego.
Vou deixar links para um estudo mais aprofundado se quiser. Vamos voar!

11. Nomeie todos os métodos da classe Object

A classe Object possui 11 métodos:
  1. Class<?> getClass() — obtém a classe do objeto atual;

  2. int hashCode() — obtém o código hash do objeto atual;

  3. boolean equals(Object obj) — compara o objeto atual com outro objeto;

  4. Clone de objeto() — cria e retorna uma cópia do objeto atual;

  5. String toString() — obtém a representação em string do objeto;

  6. void notify() — ativa uma thread aguardando no monitor deste objeto (a escolha da thread é aleatória);

  7. void notifyAll() — ativa todas as threads que aguardam no monitor deste objeto;

  8. void wait() — faz o thread atual esperar no monitor atual (congela o thread atual) até que uma chamada notify ou notifyAll ative o thread (funciona apenas em um bloco sincronizado);

  9. void wait(long timeout) — faz o thread atual esperar no monitor atual (no bloco sincronizado atual), mas com um tempo limite para sair do estado de espera (ou novamente, até que uma chamada notify ou notifyAll ative o thread);

  10. void wait(long timeout, int nanos) — este método é semelhante ao método anterior, mas com um tempo limite mais preciso;

  11. void finalize() — este método é chamado (finalmente) antes do objeto ser removido pelo coletor de lixo. É usado para limpar recursos adquiridos.

Para usar os métodos hashCode , equals , clone , toString e finalize corretamente, eles devem ser substituídos de acordo com as especificidades da tarefa atual.

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

Normalmente, ao usar try-catch-finally , o bloco final é usado para fechar recursos. Java 7 apresenta a nova instrução try-with-resources . É análogo ao try-catch-finally 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();
}
Agora isso é de alguma forma mais simples, você não acha? Além do código mais simples, há alguns outros pontos a serem observados:
  1. No try-with-resources , os recursos declarados entre parênteses (recursos 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 descobriria exatamente como fechar o recurso?

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

  2. Os blocos são executados nesta ordem:

    1. O bloco de tentativa .
    2. O bloco finalmente implícito .
    3. O bloco catch , que captura exceções que ocorrem nas etapas anteriores.
    4. O bloco finalmente explícito .

    Como regra, as exceções lançadas mais abaixo na lista interrompem aquelas lançadas mais acima.

Imagine que você está usando um try-catch-finalmente e recebe uma exceção no bloco try . Em seguida, o bloco catch especificado começa a ser executado imediatamente, no qual escrevemos outra exceção (por exemplo, com uma mensagem que descreve o erro com mais detalhes) e você deseja que o método lance essa exceção para cima. Em seguida, o bloco final é executado e uma exceção também é lançada nele. Mas desta vez um diferente. Qual dessas duas exceções esse método lançará? A exceção lançada pelo bloco final ! Mas agora chegamos a outro ponto sobre try-with-resources . Vamos considerar como o try-with-resources se comporta na mesma situação. Obtemos uma exceção no bloco try ao tentar fechar recursos no método close() , ou seja, no bloco finalmente implícito. Qual dessas exceções o bloco catch capturará ? Aquele lançado pelo bloco try ! A exceção do bloco finalmente implícito (do método loss() ) será ignorada. Esse ignorar as exceções também é chamado de supressão de exceções.

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

Operações bit a bit são operações em sequências de bits. Eles incluem operações lógicas e mudanças bit a bit. Operadores lógicos:
  • AND bit a bit — Compara valores de bits. Qualquer bit definido como 0 (falso) define o bit correspondente no resultado como 0. Ou seja, se um bit for 1 (verdadeiro) em ambos os valores comparados, o bit resultante também será 1.

    Denotado como AND ou &

    Exemplo: 10111101 e 01100111 = 00100101

  • OR bit a bit — Esta operação é o oposto da anterior. Qualquer bit definido como 1 define o bit correspondente no resultado como 1. Conseqüentemente, se o bit for 0 em ambos os valores comparados, o bit resultante também será 0.

    Denotado como OR ou |

    Exemplo: 10100101 | 01100011 = 11100111

  • NOT bit a bit — Este operador é aplicado a um único valor. Ele inverte (inverte) os bits. Ou seja, os bits que eram 1 tornam-se 0; e aqueles que eram 0 tornam-se 1.

    Denotado como NOT ou ~

    Exemplo: ~10100101 = 01011010

  • OR exclusivo bit a bit — Compara valores de bits. Se ambos os bits forem 1, então o bit resultante será 0. Se ambos os bits forem 0, então o bit resultante será 0. Em outras palavras, para que o bit resultante seja 1, apenas um dos bits deve ser 1, e o outro bit deve ser 0.

    Denotado como XOR ou ^

    Exemplo: 10100101 ^ 01100011 = 11000110

Deslocamentos bit a bit ( >> e << ) deslocam os bits do operando na direção especificada, pelo número especificado de casas. As posições vagas são preenchidas com zeros. Por exemplo:
  1. 01100011 >> 4 = 00000110
  2. 01100011 << 3 = 00011000
A exceção é quando você desloca um número negativo para a direita. Como você deve se lembrar, o primeiro bit de um número assinado indica o sinal. Se este bit for 1, então o número é negativo. Se você deslocar um número negativo, as posições vagas não serão preenchidas com zeros, mas sim com uns, pois o bit de sinal deve ser preservado. Por exemplo: 10100010 >> 2 = 11101000 Dito isto, Java tem um operador de deslocamento à direita não assinado adicional (>>>). Este operador é análogo a >>, mas quando deslocado, as posições vagas são preenchidas com 0, independentemente de o operando ser um número negativo ou positivo. Por exemplo: 10100010 >>> 2 = 00101000 Leia mais sobre operações bit a bit aqui . Explorando perguntas e respostas de uma entrevista de emprego para um cargo de desenvolvedor Java.  Parte 2 - 2Você pode usar o método hash() em HashMaps como um exemplo de mudanças bit a bit em Java. Este método é usado para determinar o hashcode interno especial da chave: Explorando perguntas e respostas de uma entrevista de emprego para um cargo de desenvolvedor Java.  Parte 2 - 3Este método permite distribuir uniformemente os dados em um HashMap, a fim de minimizar o número de colisões.

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

Um objeto é imutável se não permite que seus valores originais sejam alterados. Pode ter métodos que retornem novos objetos do mesmo tipo com valores diferentes. Alguns objetos imutáveis ​​padrão incluem:
  • sem dúvida, o tipo imutável mais famoso de Java é String;
  • instâncias das classes wrapper que agrupam tipos padrão: Boolean, Character, Byte, Short, Integer, Long, Double, Float;
  • Objetos BigInteger e BigDecimal, que geralmente são usados ​​especialmente para números GRANDES;
  • Objetos StackTraceElement que constituem um rastreamento de pilha (por exemplo, o rastreamento de pilha de uma exceção);
  • um objeto da classe File — pode modificar arquivos, mas ao mesmo tempo o próprio objeto permanece inalterado;
  • UUIDs, que são frequentemente usados ​​para identificar elementos de forma exclusiva;
  • todos os objetos de classes do pacote java.time;
  • Objetos de localidade, que são usados ​​para identificar uma região geográfica, política ou cultural.

15. Quais são as vantagens dos objetos imutáveis ​​sobre os objetos comuns?

  1. Objetos imutáveis ​​são seguros para uso em um ambiente multithread . Eles fazem isso para que você não precise se preocupar com perda de dados devido a condições de corrida. Isso é diferente de quando você trabalha com objetos comuns. Nesse caso, é preciso pensar e criar bons mecanismos ao usar o objeto em um ambiente paralelo.

  2. Objetos imutáveis ​​são bons como chaves em um mapa. Se você usar um objeto mutável como uma chave HashMap e então o estado do objeto mudar, a estrutura de dados poderá ficar confusa: o objeto ainda estará presente, mas se você usar containsKey(), poderá não encontrá-lo.

  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. Outra vantagem é a atomicidade da falha. Se um objeto imutável lançar uma exceção, ele não será deixado em um estado indesejado (quebrado).

  5. Essas classes são fáceis de testar.

  6. Você não precisa de nenhum mecanismo adicional, como um construtor de cópia ou implementação de clonagem de objeto.

Perguntas sobre POO

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

Ok, vantagens do OOP:
  1. Aplicações complexas são mais fáceis de escrever usando OOP do que programação processual, já que tudo é dividido em pequenos módulos — objetos que interagem entre si — e, como resultado, a programação é reduzida a relacionamentos entre objetos.

  2. Aplicativos escritos com OOP são muito mais fáceis de modificar (quando os princípios de design são devidamente observados).

  3. Como os dados e as operações de dados formam uma única entidade, eles não ficam espalhados por toda a aplicação (o que costuma acontecer na programação processual).

  4. O princípio do encapsulamento protege os dados mais críticos do usuário.

  5. O mesmo código pode ser reutilizado com dados diferentes porque as classes permitem criar muitos objetos, cada um com seus próprios valores.

  6. A herança e o polimorfismo também permitem reutilizar e estender o código existente (em vez de duplicar funcionalidades semelhantes).

  7. Estender um aplicativo é mais simples do que com uma abordagem processual.

  8. A abordagem OOP torna possível abstrair detalhes de implementação.

17. Conte-nos quais são as desvantagens da OOP

Infelizmente, eles também existem:
  1. OOP requer muito conhecimento teórico que deve ser dominado antes que você possa escrever qualquer coisa.

  2. As ideias 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. OOP reduz ligeiramente o desempenho de um programa devido ao aumento da complexidade 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 do que para uma abordagem processual.

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

O polimorfismo permite que objetos da mesma classe ou interface se comportem de maneira diferente. Existem dois tipos de polimorfismo, também conhecidos como ligação precoce e ligação tardia. Polimorfismo estático ou ligação precoce:
  • 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 vinculação inicial inclui métodos privados, estáticos e finais;
  • 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 o tipo de classe que aparece à esquerda do nome de uma 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 significa atribuir um objeto específico, uma referência de seu tipo ou sua superclasse;
  • a herança está associada ao polimorfismo dinâmico.

19. Forneça uma definição do princípio de abstração em OOP

Na POO, a abstração é uma forma de isolar um conjunto de características significativas de um objeto, ao mesmo tempo que exclui detalhes insignificantes. Ou seja, ao projetar um programa com abordagem OOP, você se concentra em modelos gerais, sem entrar nos detalhes de sua implementação. Em Java, a abstração é realizada através de interfaces . Por exemplo, você tem um carro e isso será uma interface. E as diversas interações com ele – por exemplo, ligar o motor, mudar de marcha – são funções que usamos sem nos aprofundar nos detalhes de implementação. Na verdade, quando você está dirigindo, 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 se você substituir a implementação de alguma funcionalidade (por exemplo, o mecanismo), talvez nem perceba. Não importa para você: você não se aprofunda nos detalhes da implementação. O que importa para você é que a ação seja realizada. Em essência, isso abstrai detalhes de implementação. Neste ponto, pararemos hoje: continua!
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION