13 março 2009

SCJP - 03 - Blocos de Inicialização


Bem, de novo, essa é uma das coisas que nós, programadores auto-didatas, não estamos muito acostumados a ver. Eu mesmo só inicializava as variáveis de instância ou dentro do construtor, ou logo depois de declaradas...





class Exemplo {
    public static final int CONSTANTE = 0;
    public String frase;

    public Exemplo() {
        this.frase = "Você tem mais o que fazer?";
    }
}

Mas, ainda assim, eu já tinha ouvido falar dos blocos de inicialização. A novidade, pra mim, é saber que existem blocos de inicialização estáticos e de instância.

class Exemplo {
    static {
        System.out.println(
            "static initialization";);
    }

    {
        System.out.println(
            "instance initialization";);
    }
}

Tão vendo, né? Nada de parâmetros, nada daquela frescura de chamada a super(), nada de um monte de coisa. Aliás, podem existir mais de um bloco de inicialização, tanto estático quanto de instância. A ordem de execução é sempre top-down (de cima pra baixo) para cada tipo de bloco de inicialização, mas cada tipo ocorre em determinado momento.

Um bloco estático de inicialização é executado apenas uma vez, quando a primeira classe é carregada (tradução acochambrada do livro). Mas quando é que isso ocorre mesmo? Bem, resolvi testar. Criei duas classes em pacotes diferentes, cujo código fonte eu vou colar ai pra vocês.

package teste.idiota;

public class Teste {

    static { 
        System.out.println(
            "static initalization");
    }

    public Teste() {
        System.out.println(
            "constutor de Teste");
    }
}


package teste;
import teste.idiota.Teste;

public class Principal {

    public Principal() {
        System.out.println(
            "constutor de principal");
    }
    
    public static void main(String[] args) {
        Principal principal 
            = new Principal();

        System.out.println(
            "ei, funcionou?");
    }
}

E então, qual a saída do programa? Se vc disse que vai executar o bloco estático da classe Teste, você errou. Agora crie mais duas classes com o seguinte codigo fonte:

package teste.idiota;

public class Teste2 {

    static { 
        System.out.println(
            "---------------");

        System.out.println(
            "teste2 static initalization (1)");
    }

    { 
        System.out.println(
            "---------------");

        System.out.println(
            "teste2 instance initalization (1)");
    }

    public Teste2() {
        System.out.println(
            "constutor de Teste2");
    }

    static { 
        System.out.println(
            "teste2 static initalization (2)");

        System.out.println(
            "---------------");
    }

    { 
        System.out.println(
            "teste2 instance initalization (2)");

        System.out.println(
            "---------------");
    }

}


package teste;
import teste.idiota.Teste2;

public class Principal2 extends Teste2{

    static { 

        System.out.println(
            "---------------");

        System.out.println(
            "principal2 static initalization (1)");
    }

    { 

        System.out.println(
            "---------------");

        System.out.println(
            "principal2 instance initalization (1)");
    }


    public Principal2() {
        super();        
        System.out.println(
            "constutor de Principal2");
    }
    
    public static void main(String[] args) {
        Principal2 p 
            = new Principal2();

        System.out.println(
            "---------------");

        Principal2 q
            = new Principal2(
               "Construtor com argumentos de Principal2");

        System.out.println(
            "---------------");

        System.out.println(
            "ei, funcionou?");
    }


    static { 
        System.out.println(
            "principal2 static initalization (2)");

        System.out.println(
            "---------------");
    }

    { 
        System.out.println(
            "principal2 instance initalization (2)");

        System.out.println(
            "---------------");
    }

}


Analizem a saída de texto. Mas notem que Principal2 é instanciada duas vezes, usando construtores diferentes. E prestem bem atenção na ordem das saídas de texto. Isso me faz concluir que os blocos estáticos são executados apenas uma vez, na primeira instanciação de uma classe, enquanto que os blocos de instância são executados todas as vezes que você instanciar a classe.

Todo bloco estático é executado antes da chamada ao construtor da superclasse, enquanto que os blocos de instância são executados logo após essa chamada. Um import sem uso não faz com que estes blocos sejam executados, pelo menos no nosso primeiro teste. Construtores sobrecarregados "compartilham" blocos de inicialização de instância.

Mas você vai me perguntar: pra que p*** servem os blocos de inicialização? Definitivamente, não me pergunte. Devem servir pra alguma coisa. Dizem que eles servem, entre outras coisas, pra inicializar um singleton, mas isso você também pode fazer usando um construtor privado...


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;