Olá a todos, hoje continuo analisando mais de 250 perguntas de entrevistas para desenvolvedores Java. Partes anteriores da análise: primeira , segunda , terceira . Então vamos continuar.
<nome da classe>{herança da classe pai} {implementação de interfaces}
Então, o que temos: {class access modifier} - apenas os modificadores public e o modificador de acesso faltante, ou seja, default , estão disponíveis para a classe . {class static} - static é um modificador que indica que esta classe é estática, aplicável apenas a classes internas (classes dentro de outras classes). {finalidade da classe} - como lembramos, este é o modificador final , na presença do qual a classe se torna não herdável (exemplo da caixa - String ). {class abstraction} - modificador - abstract , que indica que esta classe pode ter métodos não implementados. Este modificador entra em conflito com o modificador final , ou seja, apenas um deles pode estar no cabeçalho da classe, pois o modificador abstrato implica que a classe dada será herdada e suas partes abstratas serão implementadas. E final indica que esta é a versão final (final) da classe e não pode ser herdada. Na verdade, usar os dois modificadores ao mesmo tempo seria um absurdo, e o compilador não nos permitirá fazer isso. <class> é uma palavra-chave obrigatória que indica uma declaração de classe. <nome da classe> é um nome de classe simples, que é o identificador de uma classe Java específica. O nome completo da classe consiste no nome completo do pacote + . + nome de classe simples. {herança da classe pai} - especificando a classe pai (se houver) usando a palavra-chave extends . Por exemplo, .. estende ParentClass . {implementação de interface} - especificando as interfaces que esta classe implementa (se houver) usando a palavra-chave implements . Por exemplo: ... implementa FirstInterface, SecondInterface ... Bem, como exemplo de cabeçalho de classe, considere o cabeçalho da classe Lion , que herda de Cat e implementa a interface WildAnimal :
29. É possível usar return em um construtor?
Você pode, mas sem o valor de retorno à direita de return . Ou seja, você pode usar return; como construção auxiliar durante os cálculos no construtor para finalizar (interromper) com urgência a execução de mais códigos e completar a inicialização do objeto. Por exemplo, temos uma classe Cat , e se Cat for homeless - isHomeless = true , precisamos finalizar a inicialização e não preencher os demais campos (afinal, eles nos são desconhecidos, já que o gato é morador de rua):public Cat(int age, String name, boolean isHomeless) {
if (isHomeless){
this.isHomeless = isHomeless;
return;
}
this.isHomeless = isHomeless;
this.age = age;
this.name = name;
}
Mas quando se trata de valores específicos, um construtor não pode usar return para retornar um valor porque:
- ao declarar um construtor você não terá nada parecido com um tipo de retorno;
- Normalmente, o construtor é chamado implicitamente durante a instanciação;
- Um construtor não é um método: é um mecanismo separado cujo único propósito é inicializar variáveis de instância, e o operador new é responsável por criar um objeto .
30. É possível lançar uma exceção de um construtor?
Os construtores lidam com exceções exatamente da mesma maneira que os métodos. E se os métodos nos permitem lançar exceções escrevendo throws <ExceptionType> no cabeçalho do método , então o construtor nos permite fazer isso, e também ao herdar e definir um construtor herdeiro, podemos expandir o tipo de exceção. Por exemplo, IOException -> Exception (mas não vice-versa). Como exemplo de lançamento de uma exceção por um construtor, tomemos a classe Cat . Digamos que ao criá-lo queremos inserir o nome e a idade no console:public Cat() throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
this.name = reader.readLine();
this.age = Integer.parseInt(reader.readLine());
}
Como reader.readLine() lança uma IOException, nós a especificamos no cabeçalho como uma possível exceção lançada.
31. Em que elementos consiste o cabeçalho da classe? Escreva um exemplo
Falando dos elementos que compõem o cabeçalho da classe, vejamos um pequeno diagrama:- os componentes obrigatórios estarão entre colchetes <>
- opcional - em {}
public final class Lion extends Cat implements WildAnimal
32. Em quais elementos consiste o cabeçalho do método? Escreva um exemplo
Novamente, ao observar os elementos que compõem um cabeçalho de método, considere um pequeno diagrama onde:- componentes obrigatórios estão entre colchetes <>
- opcional - em {}
public static void main(String[] args) throws IOException
33. Crie um construtor padrão no objeto descendente se ele não estiver definido no objeto base (mas outro construtor estiver definido)
Não entendo completamente a pergunta em si, mas talvez isso signifique que, por exemplo, no pai temos algum construtor personalizado:public Cat(int age, String name) {
this.age = age;
this.name = name;
}
Portanto, na classe ancestral, definitivamente precisamos definir um construtor que irá preencher (chamar) o construtor pai:
public class Lion extends Cat {
public Lion(int age, String name) {
super(age, name);
}
}
34. Quando a palavra-chave this é usada?
Em Java, isso tem dois significados diferentes. 1. Como referência ao objeto atual, como this.age = 9 . Ou seja, this refere-se ao objeto no qual foi chamado e ao qual se refere o código que utiliza this . A principal função é aumentar a legibilidade do código e evitar ambiguidades. Por exemplo, se o nome do campo da classe interna e o argumento do método forem iguais:public void setName(String name) {
this.name = name;
}
Ou seja, this.name é um campo do nome do objeto que é um argumento de método. A referência this não pode ser usada em métodos estáticos. 2. this pode ser usado em um construtor na forma de uma chamada de método, como this(value) . Neste caso, será uma chamada para outro construtor da mesma classe. Resumindo, você pode chamar dois construtores ao mesmo tempo ao criar um objeto:
public Cat(int age, String name) {
this(name);
this.age = age;
}
public Cat(String name) {
this.name = name;
}
Quando um objeto Cat é criado e o primeiro construtor é chamado, ambos os campos do objeto serão chamados e inicializados com sucesso. Existem algumas nuances:
- this() só funciona no construtor.
- Uma referência a outro construtor deve estar na primeira linha do bloco construtor (corpo). Portanto, mais de um (outro) construtor de uma determinada classe não pode ser chamado em um construtor.
35. O que é um inicializador?
Pelo que entendi, nesta questão estamos falando de blocos de inicialização comuns e estatísticos. Primeiro, vamos lembrar o que é inicialização. A inicialização é criação, ativação, preparação para o trabalho, determinação de parâmetros. Colocar um programa ou componente em estado de prontidão para uso. Como você lembra, durante a criação do objeto, uma variável de classe pode ser inicializada diretamente na declaração:class Cat {
private int age = 9;
private String name = "Tom";
Ou configure-o externamente através de um construtor:
class Cat {
private int age;
private String name;
public Cat(int age, String name) {
this.age = age;
this.name = name;
}
Mas há outra maneira: definir uma variável de objeto interna por meio de um bloco de inicialização, que se parece com chaves { } dentro da classe, sem nome (como um método ou construtor):
class Cat {
private int age;
private String name;
{
age = 10;
name = "Tom";
}
Ou seja, um bloco de inicialização é um trecho de código carregado quando um objeto é criado. Normalmente, esses blocos são usados para realizar alguns cálculos complexos necessários ao carregar uma classe. Os resultados desses cálculos podem ser especificados como valores de variáveis. Além disso, além dos blocos de inicialização regulares, existem os estáticos, que têm a mesma aparência, mas possuem a palavra-chave static antes das chaves :
class Cat {
private static int age;
private static String name;
static{
age = 10;
name = "Tom";
}
Este bloco é exatamente igual ao anterior. Mas se o normal for acionado quando cada objeto for inicializado, o estático será acionado apenas uma vez, quando a classe for carregada. Nesse bloco, via de regra, também são realizados alguns cálculos complexos para a posterior inicialização de variáveis de classe estática. As mesmas restrições se aplicam a um bloco estático e a métodos estáticos: ele não pode usar dados não estáticos, bem como uma referência ao objeto atual - this . A seguir podemos ver a ordem de inicialização da classe (juntamente com seu ancestral) para uma melhor compreensão do momento em que os blocos de inicialização são acionados.
36. Para herdar uma classe public class Child estende Parent, escreva a ordem de inicialização do objeto
Quando a classe Child for carregada, a ordem de inicialização será a seguinte:- Campos estáticos da classe Parent .
- Bloco de inicialização estática para a classe Parent .
- Campos estáticos da classe Сhild .
- Bloco de inicialização estática para a classe Child .
- Campos não estáticos da classe Parent .
- Não é um bloco de inicialização estático para a classe Parent .
- Construtor da classe Parent .
- Campos não estáticos da classe Child .
- Não é um bloco de inicialização estático para a classe Child .
- Construtor da classe Child .
37. Que relações você conhece entre classes (objetos)?
Existem dois tipos de relacionamentos entre classes em Java:- Relacionamento É-A
Lion IS-A Cat
(mas nem todo gato é um leão ) A situação é exatamente a mesma com as interfaces. Se a classe Lion implementa a interface WildAnimal , então eles também estão em uma relação:
Lion IS-A WildAnimal
- Relacionamentos TEM-A
Car HAS-A Passenger
E vice-versa: se Passenger tiver referência para Car , então esta será a relação:
Passenger HAS-A Car
38. Que conexões associativas entre objetos você conhece?
Agregação e composição nada mais são do que casos especiais de associação. Agregação é um relacionamento em que um objeto faz parte de outro. Por exemplo, um passageiro pode estar num carro. Além disso, pode haver vários passageiros ou nenhum (se estamos falando de um Tesla, então o motorista não é necessário). Por exemplo:public class Car {
private List passengers = new ArrayList<>();
void setPassenger(Passenger passenger) {
passengers.add(passenger);
}
void move() {
for (Passenger passenger : passengers) {
System.out.println("Перевозка пассажира - " + passenger.toString());
}
passengers.clear();
}
}
Ou seja, não nos importamos com o número de passageiros (ou se há algum): a funcionalidade da classe Carro não depende disso. A agregação também implica que quando um objeto é usado por outro objeto, o primeiro pode ser usado em outros objetos. Por exemplo, o mesmo aluno pode ser membro de um clube de tricô e de um grupo musical de roqueiros e, ao mesmo tempo, frequentar um grupo de alunos de inglês. Como você entende, agregação é um relacionamento associativo mais flexível entre classes. A composição é uma relação ainda mais rígida quando um objeto não é apenas parte de outro objeto, mas o trabalho do outro objeto é muito dependente do primeiro. Por exemplo, um motor de carro. Embora o motor possa existir sem o carro, é inútil fora dele. Bem, um carro não pode funcionar sem motor:
public class Car {
private Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
void startMoving() {
engine.start();
...
}
A composição também implica que quando um objeto é usado por outro objeto, o primeiro não pode pertencer a mais ninguém. Se voltarmos ao nosso exemplo, um motor só pode pertencer a um carro, mas não a dois ou mais ao mesmo tempo. Provavelmente pararemos aqui hoje.
GO TO FULL VERSION