Olá pessoal! Hoje continuo minha revisão das perguntas da entrevista com desenvolvedores Java.
29. O return pode ser usado em um construtor?
Sim, mas apenas sem um valor à direita da palavra-chave return . Você pode usar retorno; como uma instrução auxiliar em um construtor para encerrar (interromper) urgentemente a execução de código adicional e finalizar a inicialização do objeto. Por exemplo, suponha que temos uma classe Cat , e se um Cat é um morador de rua ( isHomeless = true , então queremos encerrar a inicialização e não preencher os demais campos (afinal, eles nos são desconhecidos, já que o gato é um 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 se estamos falando de valores concretos, então a palavra-chave return não pode retornar um valor específico porque:
- ao declarar um construtor, você não terá nada parecido com o tipo de retorno;
- via de regra, o construtor é chamado implicitamente durante a instanciação;
- o construtor não é um método: é um mecanismo separado cujo único propósito é inicializar variáveis de instância, ou seja, estamos usando o operador new para criar um objeto.
30. Uma exceção pode ser lançada de um construtor?
Os construtores trabalham com exceções da mesma forma que os métodos. Os métodos nos permitem lançar exceções escrevendo throws <ExceptionType> no cabeçalho do método. E os construtores nos permitem fazer o mesmo. Quando herdamos e definimos o construtor de uma classe filha, podemos ampliar o tipo de exceção - por exemplo, IOException -> Exception (mas não vice-versa). Vamos usar o construtor da classe Cat como exemplo de construtor que lança uma exceção. Digamos que quando criamos um objeto, 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 escrevemos no cabeçalho como uma possível exceção lançada.
31. Quais são os elementos de um cabeçalho de classe? Escreva um exemplo
Para ilustrar os elementos que compõem um cabeçalho de classe, vejamos um pequeno esquema:- elementos obrigatórios aparecem entre colchetes <>
- elementos opcionais estão em {}
public final class Lion extends Cat implements WildAnimal
32. Quais são os elementos de um cabeçalho de método? Escreva um exemplo
Ao considerar os elementos que compõem um cabeçalho de método, consideremos novamente um pequeno esquema:- elementos obrigatórios aparecem entre colchetes <>
- elementos opcionais estão em {}
public static void main(String[] args) throws IOException
33. Crie um construtor padrão em uma classe filha se ainda não estiver definido na classe base (mas um construtor diferente estiver definido)
Não tenho certeza se entendi completamente a pergunta, mas talvez isso signifique que temos algum construtor como este na classe pai:public Cat(int age, String name) {
this.age = age;
this.name = name;
}
Nesse caso, na classe pai, definitivamente precisamos definir um construtor que irá inicializar o pai (ou seja, 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. É uma referência ao objeto atual, por exemplo, this.age = 9 . Ou seja, this refere-se ao objeto no qual é utilizado e ao qual o código com this se refere. O objetivo principal é melhorar a legibilidade do código e evitar ambiguidades. Por exemplo, se um campo de instância e um argumento de método tiverem o mesmo nome:public void setName(String name) {
this.name = name;
}
Ou seja, this.name é o campo do objeto, enquanto name é o parâmetro do método. A referência this não pode ser usada em métodos estáticos. 2. No construtor, this pode ser chamado como um método, por exemplo, this(value) . Neste caso, será uma chamada para outro construtor da mesma classe. Basicamente, você pode chamar dois construtores durante o processo de criação de um objeto:
public Cat(int age, String name) {
this(name);
this.age = age;
}
public Cat(String name) {
this.name = name;
}
Ao chamar o primeiro construtor para criar um objeto Cat , ambos os campos de instância serão inicializados com sucesso. Existem algumas nuances aqui:
- this() só funciona em um construtor.
- Uma referência a outro construtor deve estar na primeira linha do bloco construtor (corpo). Isso significa que um construtor não pode chamar mais de um (outro) construtor de sua classe.
35. O que é um inicializador?
Pelo que entendi, esta questão é sobre blocos de inicialização comuns e estáticos. Vamos primeiro lembrar o que é inicialização. A inicialização é a criação, ativação, preparação e definição de campos. Preparar um programa ou componente para estar pronto para uso. Você deve se lembrar que quando você cria um objeto, uma variável de classe pode ser inicializada imediatamente quando é declarada:class Cat {
private int age = 9;
private String name = "Tom";
Ou definido após o fato por meio do 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: você pode definir uma variável de instância usando um bloco de inicialização, que assume a forma de chaves {} dentro de uma classe, sem nome (como um método ou construtor sem nome):
class Cat {
private int age;
private String name;
{
age = 10;
name = "Tom";
}
Um bloco de inicialização é um trecho de código carregado quando um objeto é criado. Esses blocos são normalmente usados para realizar certos cálculos complexos necessários quando uma classe é carregada. Os resultados desses cálculos podem ser definidos como valores de variáveis. Além dos blocos de inicialização comuns, existem os estáticos. Eles têm a mesma aparência, mas têm a palavra-chave estática na frente da chave de abertura:
class Cat {
private static int age;
private static String name;
static{
age = 10;
name = "Tom";
}
Este bloco é igual ao anterior. Mas se o comum é executado quando cada objeto é inicializado, então o estático é executado apenas uma vez, quando a classe é carregada. Via de regra, certos cálculos complexos são realizados em um bloco estático, usado para inicializar variáveis de classe estáticas. As mesmas restrições se aplicam a um bloco estático que se aplica a métodos estáticos: você não pode usar dados não estáticos, como uma referência ao objeto atual ( this ) em um bloco estático. Agora podemos observar a ordem de inicialização da classe (juntamente com sua classe pai) para entender melhor quando exatamente os blocos de inicialização são invocados.
36. Dada uma classe pública Child que estende Parent, escreva a ordem de inicialização do objeto
Ao carregar a classe Child , a ordem de inicialização será a seguinte:- Campos de classe estática da classe Pai .
- Bloco de inicialização estática da classe Parent .
- Campos estáticos da classe Сhild .
- Bloco de inicialização estática da classe Child .
- Campos não estáticos da classe Parent .
- Bloco de inicialização não estático da classe Parent .
- Construtor da classe pai .
- Campos não estáticos da classe Сhild .
- Bloco de inicialização não estático da classe Сhild .
- O construtor da classe Сhild .
37. Que tipo de relacionamento entre classes (objetos) você conhece?
Existem dois tipos de variáveis em Java: tipos primitivos e referências a objetos completos.- Relacionamentos IS-A
Lion IS-A Cat
(mas nem todo gato é um leão ) A mesma situação existe com interfaces. Se a classe Lion implementa a interface WildAnimal , então eles também existem no relacionamento:
Lion IS-A WildAnimal
- TEM-Um relacionamento
Car HAS-A Passenger
E vice-versa: se Passenger tiver referência para Car , então esse será o relacionamento:
Passenger HAS-A Car
38. Que relações objetais associativas 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 localizado em um carro. Além do mais, pode haver vários passageiros ou nenhum (e se estivermos falando de Tesla, pode não haver motorista). 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("Transporting passenger - " + passenger.toString());
}
passengers.clear();
}
}
Ou seja, o número de passageiros (em qualquer) não é importante para nós: a funcionalidade da classe Carro não depende disso. A agregação também implica que quando outro objeto usa um objeto, o primeiro objeto pode ser usado por outros objetos. Por exemplo, o mesmo aluno pode fazer parte de um clube de tricô e de uma banda de rock e frequentar simultaneamente uma aula de espanhol. Como você pode imaginar, a agregação é um relacionamento associativo mais flexível entre classes. A composição é uma relação ainda mais estreita onde um objeto não é apenas parte de outro objeto, mas o trabalho de um objeto é muito dependente de outro. Por exemplo, um carro tem motor. Um motor pode existir sem carro, mas é inútil fora dele. E 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 outro objeto usa um objeto, o primeiro objeto não pode pertencer a nenhum outro objeto. Voltando ao nosso exemplo, um motor só pode pertencer a um carro, e não a dois ou mais ao mesmo tempo. Acho que isso é o suficiente por hoje, então vamos parar por aqui.
GO TO FULL VERSION