É 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
 
   // Construtor
   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
  protected double x, y;
 
  // Construtor
  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
  protected double radius;
 
  // Construtor
  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> )
ou
super.atributo

Veja o exemplo abaixo:
public class Ponto
  protected double x, y;
 
  // Construtor
  public Ponto(double vX, double vY) {
     x= vX;
     y= vY;
  }
 
  // 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:
public class Circulo extends Ponto
  protected double radius;
 
  // Construtor
  public Circulo(double vX, double vY, double vRadius) {
     super(vX, vY); // Aqui é chamado o construtor da classe Ponto
     radius= vRadius;
  }
 
  // 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.