Não chame métodos que podem ser sobrescritos a partir de construtores. Ao criar um objeto de subclasse, isso pode fazer com
que um método sobrescrito seja chamado antes de o objeto de subclasse ser totalmente inicializado.
Lembre-se de que ao construir um objeto de subclasse, o construtor primeiro chama um dos construtores da superclasse direta.
Se o construtor da superclasse chamar um método que pode ser sobrescrito, a versão da subclasse desse método será chamada pelo
construtor da superclasse, antes de o corpo do construtor da subclasse ter a chance de executar. Isso pode levar a erros sutis difíceis
de detectar se o método da subclasse que foi chamado depender de inicialização que ainda não foi realizada no corpo do construtor
da subclasse.
É aceitável chamar um método static a partir de um construtor. Por exemplo, um construtor e um método set muitas vezes
fazem a mesma validação para uma variável de instância particular. Se o código de validação for curto, é aceitável duplicá-lo no
construtor e no método set. Se uma validação mais longa for necessária, defina um método de validação static (normalmente um
método auxiliar private) e, então, o chame do construtor e método set. Também é aceitável que um construtor chame um método
de instância final, desde que o método não chame direta ou indiretamente um método de instância que pode ser sobrescrito.
Compreender e seguir essas boas práticas é importante para garantir que o código seja robusto e funcione corretamente em todas as situações. Quando estamos lidando com herança e construtores em Java, é especialmente importante ter cuidado para não chamar métodos que possam ser sobrescritos antes que o objeto da subclasse esteja completamente inicializado.
Um exemplo de código que viola essa prática é o seguinte:
public class Animal {
public Animal() {
fazerSom();
}
public void fazerSom() {
System.out.println("O animal fez um som.");
}
}
public class Cachorro extends Animal {
private String nome;
public Cachorro(String nome) {
this.nome = nome;
}
public void fazerSom() {
System.out.println(nome + " latiu.");
}
}
Nesse exemplo, a classe Animal
tem um construtor que chama o método fazerSom()
. A classe Cachorro
sobrescreve esse método para fazer o cachorro latir. No entanto, se um objeto Cachorro
for criado, o construtor de Animal
será chamado primeiro, e isso fará com que o cachorro tente latir antes que seu nome tenha sido inicializado. Isso pode levar a erros ou comportamento inesperado.
Para evitar esse problema, podemos modificar o construtor de Animal
para não chamar fazerSom()
, ou podemos modificar fazerSom()
para ser um método final, que não pode ser sobrescrito pelas subclasses. Outra opção seria passar o nome do cachorro para o construtor de Animal
, para que ele possa ser inicializado antes de o método fazerSom()
ser chamado.