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 5

Publicado no grupo Random-PT
Olá Olá! Os desenvolvedores Java estão em grande demanda hoje. É claro que não posso lhe fornecer uma vaga de emprego, mas tentarei ajudá-lo a adquirir novos conhecimentos e preencher algumas lacunas. Então, vamos continuar nossa revisão das perguntas da entrevista com desenvolvedores Java. Você pode encontrar links para as partes anteriores da revisão no final do artigo. Explorando perguntas e respostas de uma entrevista de emprego para um cargo de desenvolvedor Java.  Parte 5 - 1

39. Quais são os modificadores de acesso em Java? Nomeie-os. Para que são usados?

Anteriormente, abordei modificadores de acesso em uma pergunta sobre os elementos de Java usados ​​para obter o encapsulamento. Mas ainda assim, vou lembrá-lo. Modificadores de acesso em Java são palavras-chave que descrevem o nível de acesso concedido a um componente Java específico. Existem os seguintes modificadores de acesso:
  • público — um elemento marcado com este modificador é público. Em outras palavras, campos e métodos e classes declaradas com o modificador public são visíveis para outras classes tanto em seu próprio pacote quanto em pacotes externos;
  • protegido — um elemento marcado com este modificador é acessível de qualquer lugar em sua própria classe no pacote atual ou em classes derivadas, mesmo que estejam em outros pacotes;
  • default (ou nenhum modificador) se aplica implicitamente quando nenhum modificador de acesso é indicado. É semelhante ao anterior, exceto que é visível em classes derivadas encontradas em outros pacotes;
  • private — este é o mais privado de todos os modificadores. Permite acesso a um elemento apenas dentro da classe atual.

40. Cite os principais recursos dos métodos estáticos e não estáticos

A principal diferença é que os métodos estáticos pertencem a uma classe. Na verdade, você não precisa criar uma instância desta classe — métodos estáticos podem ser chamados apenas a partir do tipo de classe. Por exemplo, suponha que temos um método estático para acariciar um gato:

public class CatService {
   public static void petTheCat(Cat cat) {
       System.out.println("Pet the cat: " + cat.getName());
   }
Não precisamos de uma instância da classe CatService para chamá-lo:

Cat cat = new Cat(7, "Bobby");
CatService.petTheCat(cat);
Por outro lado, os métodos comuns estão vinculados (pertencem) a um objeto. Para chamá-los, você deve ter uma instância (objeto) na qual o método será chamado. Por exemplo, suponha que nosso gato tenha um método não estático meow() :

class Cat {
   public void meow() {
       System.out.println("Meow! Meow! Meow!");
   }
Para chamar esse método, precisamos de uma instância específica de um gato:

Cat cat = new Cat(7, "Bobby");
cat.meow();

41. Quais são as principais restrições aplicáveis ​​aos métodos estáticos e não estáticos?

Como eu disse anteriormente, a principal limitação de um método comum (não estático) é que sempre deve haver alguma instância na qual o método é chamado. Mas um método estático não exige isso. Além disso, um método estático não pode usar a referência this para elementos de um objeto, pois agora existe um objeto atual para o método.

42. O que significa a palavra-chave estática? Um método estático pode ser substituído ou sobrecarregado?

Um elemento marcado com a palavra-chave static não pertence a uma instância de uma classe, mas sim à própria classe. Ele é carregado quando a própria classe é carregada. Os elementos estáticos são os mesmos para todo o programa, enquanto os elementos não estáticos são os mesmos apenas para um objeto específico. Os seguintes elementos podem ser estáticos:
  • campos de uma classe;
  • bloco de inicialização de uma classe;
  • um método de uma classe;
  • classes aninhadas de uma classe (é claro, isso também é uma tautologia).
Um método estático não pode ser substituído: ele pertence à classe e não é herdado, mas ao mesmo tempo pode ser sobrecarregado.

43. Um método pode ser estático e abstrato ao mesmo tempo?

Já respondi isso em artigo anterior: um método não pode ser abstrato e estático ao mesmo tempo. Se um método for abstrato, isso implica que ele deve ser substituído em uma classe filha. Mas um método estático pertence à classe e não pode ser substituído. Isso cria uma contradição, que o compilador notará e ficará chateado. Se você se encontrar nesta situação, você deve pensar seriamente sobre a correção da arquitetura do seu aplicativo (dica: algo está claramente errado com ele). Explorando perguntas e respostas de uma entrevista de emprego para um cargo de desenvolvedor Java.  Parte 5 - 2

44. Os métodos estáticos podem ser usados ​​no meio de métodos não estáticos? E vice versa? Por que?

Podemos usar métodos estáticos em métodos não estáticos. Nada impede isso. Dito isto, o oposto não é possível: um método estático não pode usar um método não estático sem fazer referência a uma instância específica da classe. Lembre-se, membros estáticos de uma classe não têm acesso a uma referência this : você pode ter quantos objetos concretos da classe desejar, e cada um deles conterá uma referência this , que é uma auto-referência. Então, como determinar qual referência usar? Uh, você não. É por isso que os elementos estáticos não podem referir-se aos não estáticos sem uma referência a um objeto específico. Basicamente, um método estático só pode usar um método não estático se tiver uma referência a um objeto específico. Por exemplo, aquele que veio como argumento de método:

public static void petTheCat(Cat cat) {
   System.out.println("Pet the cat: " + cat.getName());
}
Aqui vemos que no método estático petTheCat() chama getName , um método não estático comum de um objeto Cat .

45. O que é uma interface? Pode haver uma interface final?

Lembraremos que Java não possui herança múltipla. As interfaces são uma espécie de alternativa a isso. Uma interface é como uma classe muito simplificada. Eles definem funcionalidade, mas não uma implementação concreta. Essa tarefa é deixada para as classes que implementam essas interfaces. Exemplo de interface:

public interface Animal {
    void speak();
}
Exemplo de implementação de interface por uma classe

class Cat implements Animal {
 
   @Override
   public void speak() {
       System.out.println("Meow! Meow! Meow!");
   }
}
Aqui está o que é importante saber sobre o uso de interfaces:
  1. Os métodos de interface devem conter apenas um cabeçalho. Eles não devem ter um corpo de método específico, ou seja, devem ser abstratos (embora não utilizem a palavra-chave abstract ). Existem exceções: métodos estáticos e métodos padrão, que requerem um corpo de método.

  2. Uma classe pode implementar muitas interfaces (como eu disse, interfaces são uma alternativa à herança múltipla). Os nomes das interfaces são separados por vírgulas no cabeçalho do método: class Lion implements Animal, Wild .

  3. As interfaces são criadas usando a palavra-chave interface .

  4. Quando uma classe implementa uma interface, usamos a palavra-chave implements .

  5. Uma classe que implementa uma determinada interface deve implementar todos os seus métodos abstratos ou deve declarar-se abstrata.

  6. O principal objetivo do uso de interfaces é implementar polimorfismo (para dar a um objeto a capacidade de assumir muitas formas).

  7. Como regra, os modificadores de acesso para métodos não são indicados nas interfaces: eles são públicos por padrão e você não pode especificar outros modificadores além de public . A partir do Java 9, você pode usar modificadores privados em métodos.

  8. Por padrão, as variáveis ​​de interface são static final . Em outras palavras, são constantes — devem sempre ser inicializadas diretamente na interface.

  9. Você não pode criar uma instância de uma interface.

A resposta à questão de saber se as interfaces podem ser finais é, obviamente, não. Na verdade, o objetivo de ter interfaces é que elas sejam implementadas. E como todos lembramos muito bem, o modificador final no nível da classe torna uma classe não herdável e, no caso de uma interface, não implementável. Por que precisaríamos de uma interface que não podemos implementar e usar? Você está certo - nós não faríamos! E o compilador concorda. :) Explorando perguntas e respostas de uma entrevista de emprego para um cargo de desenvolvedor Java.  Parte 5 - 3Na verdade, com a introdução de métodos de interface estáticos desde o Java 8, pode haver um ponto, mas isso não muda o fato de que uma interface não pode ser final. Só falei muito superficialmente sobre interfaces, já que se trata de um tema amplo. Para saber mais sobre isso, veja os artigos sobre interfaces em Java e a diferença entre classes abstratas e interfaces .

46. ​​Onde os campos estáticos podem ser inicializados?

Campos estáticos podem ser inicializados:
  • imediatamente após a declaração, usando sinal de igual ( = );
  • em um bloco de inicialização estático;
  • em um bloco de inicialização não estático (mas você precisa entender que toda vez que um objeto é criado, o campo estático será sobrescrito quando este bloco de inicialização for executado;
  • em um construtor de classe. Cada vez que o construtor é chamado (ou seja, cada vez que um objeto é criado usando este construtor), o campo será sobrescrito;
  • em métodos estáticos;
  • em métodos não estáticos;
  • em classes aninhadas estáticas e não estáticas, locais e anônimas.

47. O que são aulas anônimas?

Classes anônimas são classes que não possuem tipo próprio. Do que estou falando? Quando falamos sobre interfaces, mencionei que não é possível criar uma instância de um objeto: você só pode criar uma instância de uma classe que implemente uma interface. E se você não quiser que alguma classe implemente uma interface, mas precisar de um objeto que implemente a interface? E é provável que este seja o único uso do objeto. E você não precisa criar uma classe de implementação completa. Como você faria? Isso mesmo! Usando uma classe anônima! Explorando perguntas e respostas de uma entrevista de emprego para um cargo de desenvolvedor Java.  Parte 5 - 4Suponha que tenhamos alguma interface Animal :

public final interface Animal {
   public void speak();
}
Se quisermos usar uma classe anônima para instanciar uma determinada interface:

Animal cat = new Animal() {
   @Override
   public void speak() {
       System.out.println("Meow! Meow! Meow!");
   }
};
E então, você pode usar este objeto com segurança e seu método speak() implementado . Em outras palavras, a classe anônima implementa a interface e todos os seus métodos abstratos, aqui e agora. Caso contrário, não seríamos capazes de criar um objeto de interface/classe abstrata, pois haveria métodos não implementados/abstratos. Como mencionei, as classes anônimas são usadas não apenas para implementar os métodos abstratos de uma interface, mas também para implementar os métodos abstratos de uma classe abstrata. Essa abordagem é boa para situações em que um objeto é usado uma vez ou quando a implementação de um determinado método é necessária apenas uma vez. Não há necessidade de criar uma classe separada que implemente a classe/interface abstrata necessária. Mas também observo que classes anônimas raramente são usadas no trabalho. Via de regra, as aulas normais ainda têm preferência. Você pode ler mais sobre classes anônimas aqui neste artigo .

48. O que são classes primitivas?

Acho que esta é uma pergunta enganosa, possivelmente uma pegadinha, já que Java não possui classes primitivas. Existe apenas o conceito de tipos primitivos, que consideramos anteriormente. Lembramos que Java possui 8 tipos primitivos: byte , short , int , long , float , double , char , boolean .

49. O que é uma classe wrapper?

O principal problema com o uso de tipos primitivos em Java é que eles não são classes e Java é uma linguagem OOP. Ou seja, os programas escritos nesta linguagem equivalem a interações entre objetos. Mas os primitivos não são objetos. Eles não possuem métodos, mesmo os métodos padrão da classe Object . Mas e se precisarmos usar um primitivo como chave em um Map ? Então precisamos chamar seu método hashCode() . Você também pode chamar seu método equals() lá. E então? Há muitos momentos em que você precisa de uma aula, não de um primitivo. Isso torna os elementos primitivos inutilizáveis ​​e indesejáveis ​​em um programa porque violam a própria ideia de OOP. Mas a situação não é tão ruim quanto parece. Afinal, Java possui o conceito de wrappers primitivos. Em Java, todo tipo primitivo possui um gêmeo – uma classe wrapper.
  • byte -> Byte.class
  • curto -> Curto.class
  • int -> Inteiro.class
  • longo -> Long.class
  • flutuar -> Float.class
  • duplo -> Duplo.class
  • char -> Personagem.class
  • booleano -> Boolean.class
Esses tipos representam os tipos simples, mas em classes completas com vários métodos variados e úteis. Os conceitos de autoboxing e unboxing foram introduzidos para permitir que essas classes sejam usadas de maneira conveniente. Autoboxing é a conversão automática de um tipo primitivo para sua classe análoga, se necessário (por exemplo, convertendo int para Integer ). Unboxing é o processo oposto: conversão automática de uma classe wrapper primitiva em um tipo primitivo (por exemplo, conversão de Integer em int ). Graças à introdução de classes wrapper primitivas e aos processos de autoboxing e unboxing , os tipos primitivos são agora membros completos do Java como uma linguagem OOP. Explorando perguntas e respostas de uma entrevista de emprego para um cargo de desenvolvedor Java.  Parte 5 - 5Para uma discussão mais aprofundada deste tópico, recomendo fortemente a leitura deste artigo .

50. O que é uma classe aninhada? Onde é usado?

Uma classe aninhada é uma classe que é membro de outra classe. Existem 4 tipos dessas classes aninhadas em Java: 1. Classe interna Este tipo de classe é declarado diretamente no corpo de outra classe. Uma classe interna é uma classe aninhada não estática e pode acessar qualquer campo privado ou método de instância da classe externa. Como exemplo, vamos criar um zoológico que contenha um animal — uma zebra:

public class Zoo {
   class Zebra {
       public void eat(String food) {
           System.out.println("Zebra eats " + food);
       }
   }
}
Não é complicado, certo? Vamos dar uma olhada em um exemplo de criação de uma instância da classe interna:

Zoo.Zebra zebra = new Zoo().new Zebra();
zebra.eat("apple");
Como você já viu, é necessário primeiro criar um objeto da classe envolvente. Então você usa a referência do objeto para criar uma instância da classe interna. Gostaria também de salientar que uma classe interna (classe aninhada não estática) não pode ter métodos estáticos ou campos estáticos. Isso ocorre precisamente porque a classe interna está implicitamente associada a uma instância de sua classe externa e, portanto, não pode declarar nenhum método estático dentro dela mesma. 2. Classes aninhadas estáticas Essas classes são semelhantes à categoria anterior, mas possuem o modificador de acesso estático na declaração da classe. Como esse tipo de classe não tem acesso aos campos não estáticos da classe externa, ela se parece mais com uma parte estática da classe externa do que com uma classe interna. Mas esta classe tem acesso a todos os membros estáticos da classe externa, mesmo os privados. Exemplo de uma classe aninhada estática:

public class Zoo {
   static class Zebra {
       public void eat(String food) {
           System.out.println("Zebra eats " + food);
       }
   }
}
É criado de uma forma ligeiramente diferente do anterior:

Zoo.Zebra zebra = new Zoo.Zebra();
zebra.eat("apple");
Aqui não precisamos de um objeto da classe externa para criar um objeto da classe estática aninhada. Precisamos apenas saber o nome da classe aninhada para encontrá-la na classe externa. 3. Classes locais Classes locais são classes declaradas dentro do corpo de um método. Objetos de uma classe local podem ser criados e usados ​​somente dentro do método envolvente. Exemplo:

public class Zoo {
   public void feed(String animal, String food) {
       switch(animal) {
           case "zebra":
               class Zebra {
                   public void eat(String food) {
                       System.out.println("Zebra eats " + food);
                   }
               }
               Zebra zebra = new Zebra();
               zebra.eat(food);
               ...
Aqui está um exemplo:

Zoo zoo = new Zoo();
zoo.feed("zebra", "apple");
Se você não visse o código do método feed() , você nem suspeitaria que existe uma classe local, não é? Uma classe local não pode ser estática ou transiente , mas pode ser marcada como abstrata ou final (uma OU a outra, mas não ambas, pois o uso simultâneo desses dois modificadores cria um conflito). 4. Classes anônimas Já falamos sobre classes anônimas acima e, como você deve se lembrar, elas podem ser criadas a partir de duas fontes — interfaces e classes. Razões para usá-las Classes estáticas e não estáticas aninhadas são usadas porque às vezes é melhor incorporar classes pequenas em classes mais gerais e mantê-las juntas para que tenham maior coesão e um propósito comum. Basicamente, as classes aninhadas permitem aumentar o encapsulamento do seu código. Você pode optar por usar uma classe local se a classe for usada exclusivamente em um único método. Nesse caso, precisamos espalhar o código pela aplicação? Não. Dito isto, acrescentarei que na minha experiência nunca vi ninguém usar classes locais, porque se elas são necessárias ou não é altamente controverso. Você pode usar classes anônimas quando uma implementação específica de uma interface ou classe abstrata for necessária apenas uma vez. Nesse caso, não há necessidade de criar uma classe separada e completa com uma implementação. Em vez disso, mantivemos tudo simples e implementamos o(s) método(s) necessário(s) usando uma classe anônima, usamos o objeto e depois esquecemos dele (é claro, o coletor de lixo não esqueceu). Sua compreensão das classes aninhadas será aprimorada com este artigo.

51. Quais modificadores de acesso uma classe pode ter?

Existem diferentes tipos de classes e diferentes modificadores de acesso se aplicam a elas:
  • uma classe externa pode ter o modificador de acesso público ou nenhum modificador (o modificador padrão);
  • uma classe interna (classe aninhada não estática) pode ter qualquer um dos 4 modificadores de acesso;
  • uma classe estática aninhada pode ter qualquer um dos modificadores de acesso, exceto protected , porque esse modificador implica herança, o que contradiz qualquer membro estático da classe (membros estáticos não são herdados);
  • uma classe local só pode ter o modificador padrão (ou seja, nenhum modificador);
  • uma classe anônima não possui declaração de classe, portanto não possui nenhum modificador de acesso.
É aqui que terminaremos por hoje. Vejo você em breve!Explorando perguntas e respostas de uma entrevista de emprego para um cargo de desenvolvedor Java.  Parte 5 - 6
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION