De acordo com a secção anterior, um objeto do tipo JogoComObjetivo
tem três atributos de instância:
objetivo
definido na própria classe JogoComObjetivo
edesignacao
e o array jogadores
, herdados da classe Jogo
.A imagem seguinte representa o estado pretendido de um objeto do tipo JogoComObjetivo
acabado de criar (com valor inicial de "Spiral" para a designação e para o objetivo de 30).
Relembre, da secção 10.3., o que acontece quando uma instrução de criação de um objeto é executada:
A criação de uma instância de uma classe é feita em três passos:
reserva e afetação de memória para o objeto (contando com o espaço a ocupar por cada um dos seus atributos);
inicialização desses atributos com valores por omissão:
- zero para atributos de tipos primitivos numéricos,
false
paraboolean
, enull
para atributos cujo tipo não é primitivo;invocação do construtor indicado, sobre o objeto acabado de criar.
O objetivo principal dos construtores é o de inicializar os atributos de um objeto acabado de criar com valores diferentes dos valores por omissão.
Se o papel de um construtor declarado numa classe é o de inicializar os atributos nela definidos com valores específicos, então o construtor da classe JogoComObjetivo
deveria inicializar todos os atributos do novo objeto.
Mas os dois atributos herdados estão definidos como private
na classe Jogo
, ou seja, eles só estão acessíveis a partir de código da própria classe Jogo
. Então, como fazer para inicializar esses atributos a partir do construtor JogoComObjetivo
?
Esse é o papel da instrução super(designacao);
no construtor da classe JogoComObjetivo
:
/**
* Construir um jogo.
* @param designacao A designacao do jogo.
* @param objetivo A pontuacao com que se ganha este jogo
* @requires designacao != null
*/
public JogoComObjetivo (String designacao, int objetivo) {
super(designacao);
this.objetivo = objetivo;
}
O que esta instrução faz é invocar, sobre o objeto acabado de criar, o construtor definido na superclasse – neste caso, na classe Jogo
– para que os atributos aí definidos possam ser inicializados adequadamente.
Neste caso, como o construtor da classe Jogo
tem um parâmetro – a designação – a instrução super(…)
deve fornecer um valor para esse parâmetro.
Como é suposto esse valor ser decidido, para cada jogo, por quem cria o objeto, então o construtor da subclasse também requer um parâmetro com esse significado, para além de um parâmetro que recebe o valor da pontuação objetivo.
Este construtor usa o valor do primeiro parâmetro na invocação do construtor da sua superclasse e usa o valor do segundo parâmetro para inicializar o atributo objetivo
.
No fim da execução do construtor da classe JogoComObjetivo
, o novo objeto já terá todos os seus atributos inicializados (tanto os herdados como aquele que a própria classe definiu).
No Java, qualquer construtor definido explicitamente numa subclasse tem como primeira instrução, obrigatoriamente, a invocação de um construtor da sua superclasse. Esta instrução pode ser explícita ou implícita (mais adiante).
Como já exemplificado, uma forma de invocar o construtor da superclasse, a partir do corpo do construtor da subclasse, é através de uma instrução da forma super(...)
, onde …
representa os valores para os parâmetros desse construtor:
xxxxxxxxxx
public NomeClasse (...) {
super(...);
// Seguem-se outras instrucoes, se necessario
}
Deve lembrar-se de que os construtores das classes Jogador
e Jogo
(capítulos 10 e 11, respetivamente) não seguem esta regra… estes construtores aparentemente não definem como primeira instrução (nem nenhuma das seguintes) uma que invoque o construtor da sua superclasse. No entanto estas classes têm uma superclasse: a classe Object
.
Quando a primeira instrução de um construtor não é uma invocação de um construtor da superclasse,
- o compilador acrescenta implicitamente a instrução
super()
, ou seja, a invocação de um construtor da superclasse que não tem argumentos.
Se fizessemos isso no caso da classe JogoComObjetivo
,
xxxxxxxxxx
public JogoComObjetivo (int objetivo) {
this.objetivo = objetivo;
}
o compilador iria acrescentar, como primeira instrução, a instrução super();
.
Mas… na classe Jogo
não existe nenhum construtor sem parâmetros. Só existe um construtor que tem um parâmetro do tipo String
. Sabendo isto, o compilador daria erro.
Voltando aos construtores das classes Jogador
e Jogo
: como não têm uma primeira instrução em que é invocado um construtor da sua superclasse (que é Object
, como já vimos), o compilador vai acrescentar a instrução super();
. Aqui não há problema pois a classe Object
tem um único construtor, o qual não tem parâmetros.
Anterior: 14.3. Subtipos
Seguinte: 14.5. Invocação de métodos herdados