Pessoal, estou estudando para a certificação SCJP 5. Na parte de construtores fiquei com algumas dúvidas. Tentarei fazer um breve resumo do que entendi, assim se eu cometer algum erro por favor me corrijam.
1º Construtores são sempre chamados na hora da instanciação de um objeto e possuem o mesmo nome de sua classe.
2º toda classe chama o construtor de sua super classe até chegar na classe Object, que é o topo da pilha.
3º Sem sobrecarga de construtores, temos 3 diferentes situações em uma classe, são elas:
a. A classe não possui construtor algum
Quando isso acontece, o compilador inclui implicitamente um construtor padrão em nosso código. A saber, o construtor padrão é aquele que não recebe argumento algum e chama sua superclasse. Exemplo:
Class Base1 {
//Sou uma classe sem construtor algum, o compilador será legal e definirá implicitamente um
//para mim. Ele ficará exatamente assim ó: Base1(){ super() };
}
b. A classe possui construtor padrão
Class Base1{
//Oi eu sou um construtor padrão, seu eu não fosse definido pelo programador, eu seria
//colocado implicitamente aqui, até mais amiguinhos.
Base1(){
//super(); - Olá, sou um código colocado implicitamente pelo compilador, eu chamo o papai Object
}
}
c. A classe possui um construtor que não é padrão
Nesse caso o compilador entre em cena novamente com seus códigos implícitos. Vejam o exemplo:
Class Base1{
Base1(String a, int b, int c){
//super(); - Sou um código implícito
a = "Oi";
b = 1;
c = 2;
}
}
Importante lembrar que quando definimos qualquer construtor, o compilador não irá mais colocar para nós o construtor padrão.
4º Agora vamos cobrir alguns detalhes quando há sobrecarga de construtores. Vejamos um exemplo:
class Base1{
String a; int b, c;
Base1(){
super(); //Se eu não estivesse aqui implicitamente o compilador me colocaria aqui.
}
Base1(String a, int b, int c){
// super(); - Sou um código implícito - Nessa parte tenho dúvida se é assim mesmo que //acontece, se eu estiver errado por favor me corrijam.
this.a = a;
this.b = b;
this.c = c
}
Base1(String a, int b){
// super(); - Sou um código implícito
this.a = a;
this.b = b;
}
}
Bem, com esse exemplo podemos relembrar alguns conceitos:
I) A classe que tiver qualquer construtor definido, que não seja o padrão, não permite que o compilador construa implicitamente o construtor padrão, para tê-lo é necessário construí-lo explicitamente também.
II) Toda classe ao ser instanciada deve invocar o construtor da classe pai, por esse motivo que todos os método possuem implicitamente o código super(), quando não há chamada a outro construtor através do this(), como veremos adiante.
5º Ainda em sobrecarga de construtores, definiremos o exemplo novamente, com alguns novos conceitos:
class Base1{
String a; int b, c;
Base1(){
super(); //Se eu não estivesse aqui implicitamente o compilador me colocaria aqui.
}
Base1(String a, int b, int c){
this();
this.a = a;
this.b = b;
this.c = c
}
Base1(String a, int b){
this(a, b, 0);
}
}
Não me lembro agora como é chamado esse conceito, creio que seja o encadeamento de construtores, mas não sei se podemos aplicar esse nome para esse efeito na classe, o que me pareceu no livro, o encadeamento de construtores é a chamada de construtor da classe pai até chegar na classe Object.
Bem, o que acontece aqui então é que o construtor com 2 parâmetros invoca o construtor com 3 parâmetros, passando para ele os 2 parâmetros recebido mais um valor defautl, que no nosso exemplo é 0 (zero). Então no construtor de 3 parâmetros, ao receber, na primeira linha, como notamos, irá chamar o construtor padrão, que irá chamar a classe pai, e então ativar o encadeamento de construtores. Após isso, então será atribuído as variáveis da classe os valores recebido.
6º Regras para construtores em classe estendida. Vejamos o código para estudá-lo:
class Base1 {
//Base1(){ super(); } - constructor implícito
}
class Base2 extends Base1{
Base2(String a){
//super(); - Código implícito, que chamará o construtor implícito em base1, não haverão //problemas
}
}
Esse código rodaria perfeitamente, pois a classe Base2 invoca o construtor padrão de Base1, que esta definido implicitamente pelo compilador.
Agora imagine a seguinte situação:
class Base1 {
Base1(String a){
}
}
class Base2 extends Base1{
Base2(String a){
//super(); - Código implícito;
}
}
Faço a pergunta, esse código irá rodar ?? Não. Porque ?? Simples, no construtor de base2, como vemos, há o código implícito chamando o construtor padrão de Base1, sua superclasse, e como em Base1 definimos um método que recebe uma String, e como já dito, o compilador não irá colocar o construtor padrão. Resumindo em Base1 não há construtor padrão e Base2 faz chamada justamente para o construtor padrão.
Como faríamos para esse código funcionar ?? Basta adicionar uma chamada explícita para Base1(String a)(classe pai) no construtor de Base2. Para isso ficaria:
class Base2 extends Base1{
Base2(String a){
super(a);
}
}
A saber, as subclasses devem sempre chamar sua classe pai, mas para isso devem sempre fazer chamadas a construtores existentes em suas superclasses. Para não cometermos erro devemos sempre lembrar, que todo construtor possui ou uma chamada a um outro construtor de sua classe, com a chamada this(), ou uma chamada a sua superclasse com super(), não é permitido ter this() e super() no mesmo construtor. E devemos lembrar também que se um construtor não tem explicitamente this(), nem super(), implicitamente ele terá super().
Espero correções, dúvidas e sugestões.
Obrigado, by Felipe Nemeth.[color=red] [/color]