Construtores são usados para inicializar as variáveis de instância. Todo construtor por padrão possui uma chamada implícita super(), a não ser que o próprio programador coloque de forma explícita a chamada a this(). Quando é usado herança é importante verificar os construtores das classes para que não haja erros de compilação.
Exemplos práticos:
Sobrecarga X Sobrescrita
As classes herdam as características e comportamentos das superclasses. Se a classe A possui um método X e a classe B herda da classe A. A classe B possui o método X, dessa forma, a classe B pode usar essa versão herdada ou a classe B pode fazer algumas alterações no método X, ou seja, a classe B pode fazer a sobrescrita de um método. Lembre-se para ser considerado sobrescrita de método é fundamental manter a assinatura do método como o original herdado. A assinatura de um método é a junção do nome do método e os parâmetros. Já na sobrecarga o nome do método é o mesmo, porém os parâmetros são diferentes, portanto, a assinatura é outra.
Por exemplo: observe os dois métodos pertencentes a classe Contador.
public double calcularSalarioMensal(){ //método sobrescrito, herdado da classe Pessoa return super.calcularSalarioMensal()+adicional; }
public double calcularSalarioMensal(double aumento){ //método sobrecarregado, não é o mesmo método herdado da classe Pessoa return (super.calcularSalarioMensal()*aumento/100)+super.calcularSalarioMensal(); }
Classes Abstratas
São classes cujo propósito é ser estendidas por outras classes. Não é possível criar objetos de classes abstratas. Dessa forma, se no seu projeto você observou que a classe servirá apenas para fornecer seus recursos (atributos e métodos), esta é uma boa candidata a ser uma classe abstrata.
De acordo com Sierra e Bates (2005, p. 148) "no caso da classe abstrata quem se encarregará do trabalho no tempo de execução serão instâncias de uma subclasse de sua classe abstrata".
-
Referência da parte entre aspas: SIERRA, K; BATES, B. Use a cabeça Java. Tradução da 2ª edição. Editora Alta Books, 2005.
Observe as palavras abaixo:
-
Esponja;
-
Baleia;
-
Vertebrado;
-
Galinha;
-
Animal;
-
Macaco;
-
Ema;
-
Réptil;
-
Lagarto;
-
Invertebrado;
-
Mamífero;
-
Porífero;
-
Cobra;
-
Ave
Quais seriam candidatas às classes abstratas? Quais seriam candidatas às classes concretas? E como ficariam a ordenação?
package um;
public class Animal {
protected String nome;
protected int anoNascimento;
public int obterIdade(int anoAtual){
return anoAtual - anoNascimento;
}
}
package um;
public class Cachorro extends Animal{
}
package um;
public class Principal {
public static void main(String[] args) {
Animal a = new Animal();
a.nome = "Fulano";
a.anoNascimento = 0;
Cachorro c = new Cachorro();
c.nome = "Totó";
c.anoNascimento = 2020;
System.out.println(c.obterIdade(2021));
}
}
Agora retorne a classe Animal e adicione o seguinte método public abstract void comunicar();
O que acontece??
Um erro de compilação!!!
Observe que public class Animal { é uma classe concreta e esta não pode ter uma método abstrato. Um método abstrato é um método que não possui corpo, ou seja, apenas há a definição da assinatura dele. Para resolver o problema torne a classe Animal abstrata.
Troque a linha public class Animal { para public abstract class Animal {
Mas o projeto ainda apresenta erro de compilação.
Observe que ao adicionar um método abstrato, é obrigatório a classe Cachorro implementar o método. Então é preciso reescrever a classe Cachorro, como segue abaixo:
package um;
public class Cachorro extends Animal{
@Override
public void comunicar() {
System.out.println("auauau");
}
}
Mais ainda tem-se outro erro de compilação, porém na classe Principal.
Qual seria o motivo disso ???
Lembrete: classes abstratas não podem ser instanciadas.
Portanto, é preciso retirar o objeto do tipo Animal criado. Sendo assim, a classe Principal ficará assim:
package um;
public class Principal {
public static void main(String[] args) {
Cachorro c = new Cachorro();
c.nome = "Totó";
c.anoNascimento = 2020;
System.out.println(c.obterIdade(2021));
}
}
A classe Cachorro herdar a classe Animal, portanto, estas tem um relacionamento é-um. Portanto, a classe Principal pode ser escrita assim:
package um;
public class Principal {
public static void main(String[] args) {
Animal c = new Cachorro();
c.nome = "Totó";
c.anoNascimento = 2020;
System.out.println(c.obterIdade(2021));
}
}
A classe Cachorro é um Animal, porém esta pode ter também seus próprios atributos e métodos. Na classe Cachorro adicione a variável de instância double peso.
package um;
public class Cachorro extends Animal{
double peso;
@Override
public void comunicar() {
System.out.println("auauau");
}
}
Faça uma alteração na classe Principal, como mostrado a seguir:
package um;
public class Principal {
public static void main(String[] args) {
Animal c = new Cachorro();
c.nome = "Totó";
c.anoNascimento = 2020;
c.peso = 50; //erro de compilação
System.out.println(c.obterIdade(2021));
}
}
Veja que ocorre um erro de compilação, pois o objeto c é do Animal e tenta acessar uma variável que não existe na classe Animal, esta é específica do tipo Cachorro. Dessa forma, para resolver o problema, temos que fazer uma conversão (downcast). Veja o resultado:
package um;
public class Principal {
public static void main(String[] args) {
Animal c = new Cachorro();
c.nome = "Totó";
c.anoNascimento = 2020;
((Cachorro)c).peso = 50; //downcast, converte Animal para Cachorro
System.out.println(c.obterIdade(2021));
}
}