Herança

###### << Anterior - Home - Próxima >>

É o mecanismo 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**.

A classe descendente é realmente uma extensão da classe ancestral porque contém tudo o que está implementado na classe ancestral e mais o que ela própria implementa. Na verdade, a classe descendente acrescenta uma camada de código sobre a classe ancestral.

**Construtores não são aproveitados pela classe descendente**, cada classe 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

   // Construtor
   //
   public Descendente( <lista de parâmetros> )
   {
        super( <parâmetros> ); // chama o construtor ancestral
        // inicialização dos atributos
   }

   // Métodos da classe Descendente
}

```

## Referência **super**

As referências **super** e **this** 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 referências 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 argumentos> );**

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
{
  protected double x, y;

  // Construtor
  //
  public Ponto(double x, double y)
  {
     this.x= x;
     this.y= y;
  }
}

```

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
{
  protected double radius;

  // Construtor
  //
  public Circulo(double x, double y, double radius)
  {
     super(x, y); // Aqui é chamado o construtor da classe Ponto
     this.radius= radius;
  }
}

```

### **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> )**
ou
**super.atributo**

Veja o exemplo abaixo:

```
public class Ponto
{
  protected double x, y;

  // Construtor
  //
  public Ponto(double x, double y)
  {
     this.x= x;
     this.y= y;
  }

  // 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 tem acesso ao 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:

```
public class Circulo extends Ponto
{
  protected double radius;

  // Construtor
  //
  public Circulo(double x, double y, double radius)
  {
     super(x, y); // Aqui é chamado o construtor da classe Ponto
     this.radius= radius;
  }

  // Faz o escalonamento do circulo pelo fator informado
  //
  public void escale(double factor)
  {
    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.