03 março 2009

SCJP - 02 - Construtuores


Eu não sabia que era possível enumerar tantas regrinhas envolvendo construtores... Passando o lho por cima, a gente nota que muitas delas já são mais do que batidas no nosso cotidiano. Então eu resolvi pular algumas delas e escrever um post sobre coisas que eu testei, vindas do limbo.

Segue um techo de código. Copie e tentem compilar. Alguém me diz o porquê do erro tão bizarro?

class Base {
    private String teste;

    public Base(String teste){
       this.teste = teste;
    }

    public String getTeste() { 
        return teste; 
    }
}

class Derivada extends Base {
    private Integer i;

    public Derivada(Integer i) {
        this.i = i;
    }

    public Integer getI() { 
         return i; 
    }
}

public class Principal {
    public static void main(String[] args) {
        Derivada derivada = new Derivada(1);

        System.out.println(
            derivada.getI());

    }
}



Por incrivel que pareça, isso não tem absolutamente nada a ver com erro de digitação. Agora, alterem o construtor da classe Derivada, conforme abaixo:

public Derivada(Integer i) {
    super("teste");
    this.i = i;
}

Agora, o código compila. Mas... Por quê?

Resposta: Ambas as duas classes não possuem construtor padrão. Sim, e daí? O compilador insere implicitamente uma chamada a super() como primeira instrução de qualquer construtor, a menos que já exista uma chamada a this(). O método super() chama o construtor sem argumentos da superclasse, enquanto que o método this() chama o construtor sem argumentos definido na própria classe. Logo, a chamada a super() feita implicitamente dentro do construtor de Derivada não surte efeito, porque a classe Base também não tem construtor padrão.

Mas... se o compilador java é algo tão robusto, por que, então, ele não detectaria esse tipo de erro? O compilador gera um código semelhante ao abaixo:

class Derivada extends Base {
    private Integer i;

    public Derivada(Integer i) {
        super();
        this.i = i;
    }

    public Integer getI() { 
         return i; 
    }
}

E então, ao tentar fazer referência ao trecho de código que realiza a invocação equivocada, o compilador utiliza o seu código, não o gerado por ele. É ai que fica parecendo que é o "{" que não consegue ser interpretado pelo compiilador...

Então, por via de regra: sempre que você definir um construtor não padrão na sua classe, implemente um construtor sem argumentos. Se você não implementar nenhum construtor, o compilador implementará um construtor padrão pra você.

  • O construtor padrão tem o mesmo modificador de acesso da classe.
  • O construtor padrão não possui lista de argumentos.
  • O construtor padrão tem uma chamada ao construtor da superclasse (super()).

Depois dessa explicação furada, dêem uma olhada na pagina 138 do livro da certificação, versão em inglês. Vejam que naquela situação, a chamada a super() é feita explicitamente, tornando o erro gerado pelo compilador um pouco mais legível:

public Derivada(Integer i) {
    super();
    this.i = i;
}


Agora sim parece ser mais óbvio dizer que o compilador tentou chamar super() e não achou um construtor sem argumentos na superclasse. O mais estranho disso tudo é que o livro da SCJP diz que é óbvio concluir que construtores não são herdados. Eu juro que não vi obviedade nenhuma nisso... Eu demorei pra concluir que, pelo fato de construtores não possuirem um tipo de retorno, nem poderem ser utilizados dentro de métodos, eles não podem ser considerados métodos, e daí concluir que eles não são herdados. Acho que nem a propria Sun explica isso direito :(

Creative Commons License
Esta obra está licenciada sob uma Licença Creative Commons.
Comentários
0 Comentários

0 comments:

Postar um comentário

Regras são chatas, mas...

- Seu comentário precisa ter relação com o assunto do post;
- Em hipótese alguma faça propaganda de outros blogs ou sites;
- Não inclua links desnecessários no conteúdo do seu comentário;
- Se quiser deixar sua URL, comente usando a opção OpenID;
- CAIXA ALTA, miguxês ou erros de ortografia não serão tolerados;
- Ofensas pessoais, ameaças e xingamentos não são permitidos;