PooPerrotti - Herança
PooPerrotti Home
Tipos e variáveis
Estrutura das classes
Assinatura de métodos
Referência this
É o processo pelo qual uma classe herda atributos e métodos de outra classe. A classe original é chamada de ancestral ou super-classe e a nova classe (herdeira) é a classe descendente ou sub-classe. Se uma classe é descendente de outra, então todos os métodos e atributos públicos e protegidos da classe ancestral ficam automaticamente disponíveis na classe descendente, sem ser necessária nenhuma implementação adicional. A herança é indicada no Java usando a palavra reservada extends.
Construtores não são herdados, a classe descendente precisa implementar seu próprio conjunto de construtores e dentro de cada um deles chamar algum construtor da classe ancestral para que o objeto seja construído corretamente. A maneira de chamar o construtor da classe ancestral é usando a palavra reservada super (veja abaixo) no lugar do nome do construtor.
public class Descendente extends Ancestral {
// Aqui a declaração de atributos acrescentados pela classe Descendente
public Descendente( <lista de parâmetros> )
super( <parâmetros> ); // chama o construtor ancestral
// inicialização dos atributos
// Métodos da classe Descendente
A palavra reservada super (referência)
As palavras reservadas super e this são referências que podem ser usadas dentro da classe para acessar métodos, atributos e construtores da classe ancestral (super) ou da própria classe (this). As duas palavras só podem ser usadas dentro dos métodos e construtores das classes.
super faz sempre referência à classe ancestral, então só pode ser usada dentro de uma classe descendente para acessar construtores, métodos e atributos da classe ancestral.
Para acesso de construtores da classe imediatamente ancestral
Para entender o processo de construção de objetos, basta lembrar que do ponto de vista do Java uma classe descendente é uma extensão da classe ancestral. Então, antes de construir a parte do objeto que é uma extensão (um acréscimo), primeiro temos que construir o que vai ser estendido (o núcleo - a parte ancestral do objeto). Para que este mecanismo de construção funcione é responsabilidade dos construtores da classe descendente chamar algum construtor da classe imediatamente ancestral antes de executar qualquer código e para isso é usada a referência super. Neste caso com a seguinte sintaxe:
super( <lista de parametros> );
A lista de argumentos na chamada deve combinar com a lista de parâmetros de algum construtor da classe ancestral. Será chamado o construtor cuja assinatura combina com a chamada. Considere o exemplo abaixo:
public class Ponto
public Ponto(double vX, double vY) {
x= vX;
y= vY;
No exemplo, a classe Ponto define apenas um construtor que exige dois parâmetros do tipo double. Como a classe definiu um construtor, o Java não criou um construtor padrão para a classe, então a única maneira de construir objetos da classe Ponto é chamando esse construtor.
Portanto, qualquer classe descendente direta da classe Ponto, será obrigada a implementar um construtor que chame o construtor de Ponto antes de executar qualquer código e é para isso que a referência super é usada. Veja o exemplo abaixo de uma classe descendente de Ponto:
public class Circulo extends Ponto
public Circulo(double vX, double vY, double vRadius) {
super(vX, vY); // Aqui é chamado o construtor da classe Ponto
radius= vRadius;
Para acesso de métodos e atributos ancestrais
Normalmente não é preciso usar super para acessar métodos e atributos da classe ancestral. Se forem públicos ou protegidos eles estarão disponíveis na classe descendente sem ser necessária uma referência à classe ancestral. Entretanto, métodos e atributos da classe ancestral podem ser sobrepostos (overriding) pela classe descendente e nesse caso é necessário usar a palavra super quando se quer acessar a implementação da classe ancestral. Para isso usa-se a seguinte sintaxe:
super.metodo( <lista de argumentos> )
super.atributo
// Faz o escalonamento do ponto pelo fator informado
public void escale(double factor){
x *= factor;
y *= factor;
O método escale agora está implementado pela classe Ponto. Sendo público, qualquer classe descendente de Ponto herda o método e pode chamá-lo sem nenhuma referência adicional. Mas vejamos o que acontece se este método for reescrito por uma classe descendente como no exemplo abaixo:
// Faz o escalonamento do circulo pelo fator informado
super.escale(factor); // chama o método escale da classe ancestral
radius *= factor;
Note que apesar do método escale estar disponível para a classe Circulo, a implementação da classe Ponto não é suficiente para fazer o escalonamento de um círculo porque o raio também precisa ser considerado. Então a classe Circulo precisa reescrever o método escale para escalonar também o raio. Para aproveitar o código já implementado pela classe Ponto, a versão ancestral do método escale é chamada usando a palavra super.
Importante: Note que neste exemplo o uso de super é obrigatório. Se a chamada ao método escale for feita sem a referência super, então o método escale da classe Circulo é que vai ser chamado. Isso provocaria um loop infinito que termina com uma sonora exceção, já que teríamos um método chamando ele mesmo (recursivo) sem nenhum critério de parada.