Entrevista Java: perguntas OOP
1. Quais recursos o Java possui?
Responder:-
Conceitos de OOP:
- orientação a objetos;
- herança;
- encapsulamento;
- polimorfismo;
- abstração.
-
Plataforma cruzada: um programa Java pode ser executado em qualquer plataforma sem quaisquer modificações. A única coisa que você precisa é de uma JVM (máquina virtual Java) instalada.
-
Alto desempenho: JIT (compilador Just In Time) permite alto desempenho. JIT converte o bytecode em código de máquina e então a JVM inicia a execução.
- Multithreading: Um thread de execução conhecido como
Thread
. A JVM cria um thread chamadomain thread
. Um programador pode criar vários threads herdando da classe Thread ou implementando uma interfaceRunnable
.
2. O que é herança?
Herança significa que uma classe pode herdar (“ estender ”) outra classe. Dessa forma, você pode reutilizar o código da classe da qual você herdou. A classe existente é conhecida comosuperclass
, e a que está sendo criada é conhecida como subclass
. Eles também dizem parent
e child
.
public class Animal {
private int age;
}
public class Dog extends Animal {
}
onde Animal
está parent
e Dog
- child
.
3. O que é encapsulamento?
Essa pergunta geralmente surge durante entrevistas com desenvolvedores Java. O encapsulamento oculta a implementação usando modificadores de acesso, usando getters e setters. Isso é feito para fechar o acesso para uso externo nos locais onde os desenvolvedores julgarem necessário. Um exemplo acessível da vida é um carro. Não temos acesso direto ao funcionamento do motor. Para nós, a tarefa é colocar a chave na ignição e ligar o motor. E quais processos ocorrerão nos bastidores não é da nossa conta. Além disso, a nossa interferência nesta atividade pode levar a uma situação imprevisível, pela qual podemos quebrar o carro e nos machucar. Exatamente a mesma coisa acontece na programação. Bem descrito na Wikipedia . Há também um artigo sobre encapsulamento no JavaRush .4. O que é polimorfismo?
Polimorfismo é a capacidade de um programa usar objetos de forma idêntica com a mesma interface sem informações sobre o tipo específico desse objeto. Como se costuma dizer, uma interface – muitas implementações. Com o polimorfismo, você pode combinar e usar diferentes tipos de objetos com base em seu comportamento comum. Por exemplo, temos uma classe Animal, que possui dois descendentes - Cachorro e Gato. A classe genérica Animal tem um comportamento comum para todos - fazer um som. No caso em que precisamos reunir todos os descendentes da classe Animal e executar o método “fazer som”, utilizamos as possibilidades de polimorfismo. Será assim que será:List<Animal> animals = Arrays.asList(new Cat(), new Dog(), new Cat());
animals.forEach(animal -> animal.makeSound());
Então o polimorfismo nos ajuda. Além disso, isto também se aplica a métodos polimórficos (sobrecarregados). Prática de uso de polimorfismo
Perguntas da entrevista - Sintaxe Java
5. O que é um construtor em Java?
As seguintes características são válidas:- Quando um novo objeto é criado, o programa utiliza o construtor apropriado para isso.
- Um construtor é como um método. Sua peculiaridade é que não há elemento de retorno (inclusive void), e seu nome é igual ao nome da classe.
- Se nenhum construtor for escrito explicitamente, um construtor vazio será criado automaticamente.
- O construtor pode ser substituído.
- Se um construtor com parâmetros foi criado, mas você também precisa de um sem parâmetros, é necessário escrevê-lo separadamente, pois ele não é criado automaticamente.
6. Quais são as duas classes que não herdam de Object?
Não se deixe enganar pelas provocações, tais classes não existem: todas as classes diretamente ou através de ancestrais são herdadas da classe Object!7. O que é variável local?
Outra pergunta popular durante uma entrevista com um desenvolvedor Java. Uma variável local é uma variável definida dentro de um método e existe até o momento em que o método é executado. Assim que a execução terminar, a variável local deixará de existir. Aqui está um programa que usa a variável local helloMessage no método main():public static void main(String[] args) {
String helloMessage;
helloMessage = "Hello, World!";
System.out.println(helloMessage);
}
8. O que é variável de instância?
Variável de instância é uma variável definida dentro de uma classe e existe até o momento em que o objeto existe. Um exemplo é a classe Bee, que possui duas variáveis nectarCapacity e maxNectarCapacity:public class Bee {
/**
* Current nectar capacity
*/
private double nectarCapacity;
/**
* Maximal nectar that can take bee.
*/
private double maxNectarCapacity = 20.0;
...
}
9. O que são modificadores de acesso?
Modificadores de acesso são uma ferramenta que permite personalizar o acesso a classes, métodos e variáveis. Existem os seguintes modificadores, ordenados em ordem crescente de acesso:private
- usado para métodos, campos e construtores. O nível de acesso é apenas a classe dentro da qual é declarado.package-private(default)
- pode ser usado para aulas. Acesso apenas em um pacote específico no qual é declarada uma classe, método, variável, construtor.protected
— o mesmo acesso quepackage-private
+ para as classes que herdam de uma classe com o modificadorprotected
.public
- também usado para aulas. Acesso total em todo o aplicativo.
10. O que são métodos de substituição?
A substituição de método ocorre quando o filho deseja alterar o comportamento da classe pai. Se você quiser que o que está no método pai seja executado, você pode usar uma construção como super.methodName() no filho, que fará o trabalho do método pai, e só então adicionar lógica. Requisitos a serem atendidos:- a assinatura do método deve ser a mesma;
- o valor de retorno deve ser o mesmo.
11. O que é uma assinatura de método?
Uma assinatura de método é um conjunto do nome do método e dos argumentos que o método aceita. Uma assinatura de método é um identificador exclusivo para um método ao sobrecarregá-los.12. O que é sobrecarga de método?
A sobrecarga de métodos é uma propriedade do polimorfismo em que, alterando a assinatura do método, é possível criar métodos diferentes para as mesmas ações:- mesmo nome de método;
- argumentos diferentes;
- pode haver um tipo de retorno diferente.
add()
of ArrayList
pode ser sobrecarregado da seguinte maneira e realizará a adição de maneira diferente, dependendo dos argumentos recebidos:
add(Object o)
- simplesmente adiciona um objeto;add(int index, Object o)
— adiciona um objeto a um índice específico;add(Collection<Object> c)
— adiciona uma lista de objetos;add(int index, Collection<Object> c)
— adiciona uma lista de objetos, começando em um determinado índice.
13. O que é Interface?
Herança múltipla não é implementada em Java, então para superar esse problema, foram adicionadas interfaces como as conhecemos ;) Por muito tempo, as interfaces só tinham métodos sem implementá-los. Como parte desta resposta, falaremos sobre eles. Por exemplo:
public interface Animal {
void makeSound();
void eat();
void sleep();
}
Algumas nuances decorrem disso:
- todos os métodos da interface são públicos e abstratos;
- todas as variáveis são public static final;
- as classes não os herdam (estende), mas os implementam (implementam). Além disso, você pode implementar quantas interfaces desejar.
- classes que implementam uma interface devem fornecer implementações de todos os métodos que a interface possui.
public class Cat implements Animal {
public void makeSound() {
// method implementation
}
public void eat() {
// implementation
}
public void sleep() {
// implementation
}
}
14. Qual é o método padrão na Interface?
Agora vamos falar sobre métodos padrão. Para quê, para quem? Esses métodos foram adicionados para tornar tudo “seu e nosso”. Do que estou falando? Sim, por um lado foi necessário adicionar novas funcionalidades: lambdas, Stream API, por outro lado foi necessário deixar o que o Java é famoso - a retrocompatibilidade. Para isso, foi necessário introduzir soluções prontas nas interfaces. Foi assim que os métodos padrão chegaram até nós. Ou seja, o método padrão é um método implementado na interface que possui a palavra-chavedefault
. Por exemplo, o método bem conhecido stream()
no Collection
. Confira, essa interface não é tão simples quanto parece ;). Ou também um método igualmente conhecido forEach()
do Iterable
. Também não existia até que os métodos padrão foram adicionados. A propósito, você também pode ler sobre isso no JavaRush .
15. Como então herdar dois métodos padrão idênticos?
Com base na resposta anterior sobre qual é o método padrão, você pode fazer outra pergunta. Se você pode implementar métodos em interfaces, então teoricamente você pode implementar duas interfaces com o mesmo método, e como fazer isso? Existem duas interfaces diferentes com o mesmo método:interface A {
default void foo() {
System.out.println("Foo A");
}
}
interface B {
default void foo() {
System.out.println("Foo B");
}
}
E existe uma classe que implementa essas duas interfaces. Para evitar incertezas e compilar o código, precisamos substituir o método foo()
na classe C
e podemos simplesmente chamar um método foo()
de qualquer uma das interfaces nela contidas - A
ou B
. Mas como escolher um método de interface específico А
ou В
? Existe uma estrutura como esta para isso A.super.foo()
:
public class C implements A, B {
@Override
public void foo() {
A.super.foo();
}
}
ou:
public class C implements A, B {
@Override
public void foo() {
B.super.foo();
}
}
Assim, um método foo()
de classe C
usará o método padrão foo()
da interface A
ou um método foo()
da interface B
.
16. O que são métodos e classes abstratos?
Java possui uma palavra reservadaabstract
que é usada para denotar classes e métodos abstratos. Primeiro, algumas definições. Um método abstrato é um método criado sem implementação com uma palavra-chave abstract
em uma classe abstrata. Ou seja, este é um método como na interface, apenas com a adição de uma palavra-chave, por exemplo:
public abstract void foo();
Uma classe abstrata é uma classe que também possui abstract
a palavra:
public abstract class A {
}
Uma classe abstrata possui vários recursos:
- um objeto não pode ser criado com base nele;
- pode ter métodos abstratos;
- pode não ter métodos abstratos.
17. Qual é a diferença entre String, String Builder e String Buffer?
Os valoresString
são armazenados em um conjunto de strings constante. Depois que uma linha for criada, ela aparecerá neste pool. E não será possível excluí-lo. Por exemplo:
String name = "book";
...a variável se referirá ao pool de strings Pool de strings constante Se você definir o nome da variável com um valor diferente, obterá o seguinte:
name = "pen";
Conjunto de strings constante Portanto, esses dois valores permanecerão lá. Buffer de string:
- os valores
String
são armazenados na pilha. Se o valor for alterado, o novo valor será substituído pelo antigo; String Buffer
sincronizado e, portanto, thread-safe;- Devido à segurança da rosca, a velocidade de operação deixa muito a desejar.
StringBuffer name = "book";
Assim que o valor do nome muda, o valor na pilha muda: StringBuilder Exatamente o mesmo que StringBuffer
, só que não é thread-safe. Portanto, sua velocidade é claramente maior que em StringBuffer
.
18. Qual é a diferença entre uma classe abstrata e uma interface?
Classe abstrata:- classes abstratas possuem um construtor padrão; é chamado toda vez que um filho desta classe abstrata é criado;
- contém métodos abstratos e não abstratos. Em geral, pode não conter métodos abstratos, mas ainda assim ser uma classe abstrata;
- uma classe que herda de uma classe abstrata deve implementar apenas métodos abstratos;
- uma classe abstrata pode conter uma variável de instância (veja a pergunta nº 5).
- não tem construtor e não pode ser inicializado;
- apenas métodos abstratos devem ser adicionados (sem contar os métodos padrão);
- classes que implementam uma interface devem implementar todos os métodos (sem contar os métodos padrão);
- interfaces só podem conter constantes.
19. Por que acessar um elemento em um array leva O(1)?
Esta pergunta é literalmente da última entrevista. Como aprendi mais tarde, esta pergunta é feita para ver como uma pessoa pensa. É claro que há pouco significado prático neste conhecimento: basta conhecer este facto. Primeiramente, precisamos esclarecer que O(1) é uma designação para a complexidade de tempo de um algoritmo quando a operação ocorre em tempo constante. Ou seja, esta designação é a execução mais rápida. Para responder a esta pergunta, precisamos entender o que sabemos sobre arrays. Para criar um arrayint
, devemos escrever o seguinte:
int[] intArray = new int[100];
Várias conclusões podem ser tiradas desta gravação:
- Ao criar um array, seu tipo é conhecido. Se o tipo for conhecido, fica claro qual será o tamanho de cada célula do array.
- Sabe-se qual será o tamanho do array.
Como você obtém acesso O(1) a objetos em um ArrayList?
Esta questão segue imediatamente a anterior. É verdade que quando trabalhamos com um array e nele existem primitivos, sabemos de antemão qual é o tamanho desse tipo no momento de sua criação. Mas e se houver um esquema como o da imagem: e quisermos criar uma coleção com elementos do tipo A, e adicionar diferentes implementações - B, C, D:List<A> list = new ArrayList();
list.add(new B());
list.add(new C());
list.add(new D());
list.add(new B());
Nessa situação, como você pode entender qual será o tamanho de cada célula, pois cada objeto será diferente e poderá ter campos adicionais diferentes (ou ser completamente diferentes). O que fazer? Aqui a questão é colocada de forma a confundir e confundir. Sabemos que na verdade a coleção não armazena objetos, mas apenas links para esses objetos. E todos os links têm o mesmo tamanho, e isso é conhecido. Portanto, contar o espaço aqui funciona da mesma forma que na questão anterior.
21. Autoboxing e unboxing
Antecedentes históricos: autoboxing e autounboxing são uma das principais inovações do JDK 5. Autoboxing é o processo de conversão automática de um tipo primitivo para a classe wrapper apropriada. Auto-unboxing - faz exatamente o oposto do auto-boxing - converte uma classe wrapper em uma primitiva. Mas se houver um valor de wrappernull
, uma exceção será lançada durante a descompactação NullPointerException
.
Primitivo correspondente - wrapper
Primitivo | Wrapper de classe |
---|---|
boleano | boleano |
interno | Inteiro |
byte | Byte |
Caracteres | Personagem |
flutuador | Flutuador |
longo | Longo |
curto | Curto |
dobro | Dobro |
A embalagem automática ocorre:
-
ao atribuir a uma primitiva uma referência à classe wrapper:
ANTES do Java 5:
//manual packaging or how it was BEFORE Java 5. public void boxingBeforeJava5() { Boolean booleanBox = new Boolean(true); Integer intBox = new Integer(3); // and so on to other types } после Java 5: //automatic packaging or how it became in Java 5. public void boxingJava5() { Boolean booleanBox = true; Integer intBox = 3; // and so on to other types }
-
ao passar um primitivo como argumento para um método que espera um wrapper:
public void exampleOfAutoboxing() { long age = 3; setAge(age); } public void setAge(Long age) { this.age = age; }
A descompactação automática ocorre:
-
quando atribuímos uma variável primitiva à classe wrapper:
//before Java 5: int intValue = new Integer(4).intValue(); double doubleValue = new Double(2.3).doubleValue(); char c = new Character((char) 3).charValue(); boolean b = Boolean.TRUE.booleanValue(); //and after JDK 5: int intValue = new Integer(4); double doubleValue = new Double(2.3); char c = new Character((char) 3); boolean b = Boolean.TRUE;
-
Em casos com operações aritméticas. Eles se aplicam apenas a tipos primitivos; para isso você precisa fazer o unboxing do primitivo.
// Before Java 5 Integer integerBox1 = new Integer(1); Integer integerBox2 = new Integer(2); // for comparison it was necessary to do this: integerBox1.intValue() > integerBox2.intValue() //в Java 5 integerBox1 > integerBox2
-
quando passado para um wrapper em um método que aceita a primitiva correspondente:
public void exampleOfAutoboxing() { Long age = new Long(3); setAge(age); } public void setAge(long age) { this.age = age; }
22. Qual é a palavra-chave final e onde usá-la?
A palavra-chavefinal
pode ser usada para variáveis, métodos e classes.
- Uma variável final não pode ser reatribuída a outro objeto.
- a classe final é estéril)) não pode ter herdeiros.
- O método final não pode ser substituído em um ancestral.
variáveis finais
;Java nos dá duas maneiras de criar uma variável e atribuir algum valor a ela:- Você pode declarar uma variável e inicializá-la posteriormente.
- Você pode declarar uma variável e atribuí-la imediatamente.
public class FinalExample {
//final static variable, which is immediately initialized:
final static String FINAL_EXAMPLE_NAME = "I'm likely final one";
//final is a variable that is not initialized, but will only work if
//initialize this in the constructor:
final long creationTime;
public FinalExample() {
this.creationTime = System.currentTimeMillis();
}
public static void main(String[] args) {
FinalExample finalExample = new FinalExample();
System.out.println(finalExample.creationTime);
// final field FinalExample.FINAL_EXAMPLE_NAME cannot be assigned
// FinalExample.FINAL_EXAMPLE_NAME = "Not you're not!";
// final field Config.creationTime cannot be assigned
// finalExample.creationTime = 1L;
}
}
A variável Final pode ser considerada uma constante?
Como não poderemos atribuir um novo valor a uma variável final, parece que estas são variáveis constantes. Mas isso é apenas à primeira vista. Se o tipo de dados ao qual a variável se refere forimmutable
, então sim, é uma constante. Mas se o tipo de dado mutable
for mutável, através de métodos e variáveis será possível alterar o valor do objeto ao qual final
a variável se refere, e neste caso não pode ser chamada de constante. Portanto, o exemplo mostra que algumas das variáveis finais são realmente constantes, mas outras não, e podem ser alteradas.
public class FinalExample {
//immutable final variables:
final static String FINAL_EXAMPLE_NAME = "I'm likely final one";
final static Integer FINAL_EXAMPLE_COUNT = 10;
// mutable filter variables
final List<String> addresses = new ArrayList();
final StringBuilder finalStringBuilder = new StringBuilder("constant?");
}
Variáveis finais locais
Quandofinal
uma variável é criada dentro de um método, ela é chamada local final
de variável:
public class FinalExample {
public static void main(String[] args) {
// This is how you can
final int minAgeForDriveCar = 18;
// or you can do it this way, in the foreach loop:
for (final String arg : args) {
System.out.println(arg);
}
}
}
Podemos usar a palavra-chave final
em loop estendido for
porque após a conclusão da iteração do loop, for
uma nova variável é criada a cada vez. Mas nada disso se aplica a um loop for normal, então o código abaixo gerará um erro em tempo de compilação.
// final local changed j cannot be assigned
for (final int i = 0; i < args.length; i ++) {
System.out.println(args[i]);
}
Aula final
Você não pode estender uma classe declarada comofinal
. Simplificando, nenhuma classe pode herdar desta. Um ótimo exemplo final
de classe no JDK é String
. O primeiro passo para criar uma classe imutável é marcá-la como final
, para que não possa ser estendida:
public final class FinalExample {
}
// Compilation error here
class WantsToInheritFinalClass extends FinalExample {
}
Métodos finais
Quando um método é marcado como final, ele é chamado de método final (lógico, certo?). O método Final não pode ser substituído em uma classe descendente. A propósito, os métodos da classe Object - wait() e notify() - são finais, portanto não temos a oportunidade de substituí-los.public class FinalExample {
public final String generateAddress() {
return "Some address";
}
}
class ChildOfFinalExample extends FinalExample {
// compile error here
@Override
public String generateAddress() {
return "My OWN Address";
}
}
Como e onde usar final em Java
- use a palavra-chave final para definir algumas constantes em nível de classe;
- crie variáveis finais para objetos quando não quiser que eles sejam modificados. Por exemplo, propriedades específicas do objeto que podemos usar para fins de registro;
- se não quiser que a aula seja estendida, marque-a como final;
- se você precisar criar uma classe imutável<, precisará torná-la final;
- se você deseja que a implementação de um método não mude em seus descendentes, designe o método como
final
. Isto é muito importante para garantir que a implementação não mude.
23. O que é mutável e imutável?
Mutável
Mutáveis são objetos cujos estados e variáveis podem ser alterados após a criação. Por exemplo, classes como StringBuilder, StringBuffer. Exemplo:public class MutableExample {
private String address;
public MutableExample(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
// this setter can change the name field
public void setAddress(String address) {
this.address = address;
}
public static void main(String[] args) {
MutableExample obj = new MutableExample("first address");
System.out.println(obj.getAddress());
// update the name field, so this is a mutable object
obj.setAddress("Updated address");
System.out.println(obj.getAddress());
}
}
Imutável
Imutáveis são objetos cujos estados e variáveis não podem ser alterados após a criação do objeto. Por que não uma ótima chave para um HashMap, certo?) Por exemplo, String, Integer, Double e assim por diante. Exemplo:// make this class final so no one can change it
public final class ImmutableExample {
private String address;
ImmutableExample (String address) {
this.address = address;
}
public String getAddress() {
return address;
}
//remove the setter
public static void main(String[] args) {
ImmutableExample obj = new ImmutableExample("old address");
System.out.println(obj.getAddress());
// Therefore, do not change this field in any way, so this is an immutable object
// obj.setName("new address");
// System.out.println(obj.getName());
}
}
24. Como escrever uma classe imutável?
Depois de descobrir o que são objetos mutáveis e imutáveis, a próxima pergunta é natural - como escrevê-los? Para escrever uma classe imutável e imutável, você precisa seguir etapas simples:- tornar a aula final.
- torne todos os campos privados e crie apenas getters para eles. Os setters, é claro, não são necessários.
- Torne todos os campos mutáveis finais para que o valor só possa ser definido uma vez.
- inicialize todos os campos através do construtor, realizando uma cópia profunda (ou seja, copiando o próprio objeto, suas variáveis, variáveis de variáveis, e assim por diante)
- clonar objetos variáveis mutáveis em getters para retornar apenas cópias de valores, não referências a objetos reais.
/**
* An example of creating an immutable object.
*/
public final class FinalClassExample {
private final int age;
private final String name;
private final HashMap<String, String> addresses;
public int getAge() {
return age;
}
public String getName() {
return name;
}
/**
* Clone the object before returning it.
*/
public HashMap<String, String> getAddresses() {
return (HashMap<String, String>) addresses.clone();
}
/**
* In the constructor, deep copy the mutable objects.
*/
public FinalClassExample(int age, String name, HashMap<String, String> addresses) {
System.out.println("Performing a deep copy in the constructor");
this.age = age;
this.name = name;
HashMap<String, String> temporaryMap = new HashMap<>();
String key;
Iterator<String> iterator = addresses.keySet().iterator();
while (iterator.hasNext()) {
key = iterator.next();
temporaryMap.put(key, addresses.get(key));
}
this.addresses = temporaryMap;
}
}
GO TO FULL VERSION