quarta-feira, maio 23, 2007

Modificador Static

Você sabe o que significa a bendita palavra static no Java?
Vejo muita gente fazendo confusão sobre esse assunto, sem entender o que é ou quando usar etc...
Bem, como de costume, lá vem um exemplinho básico do emprego de variáveis estáticas.

Imagine que nós estamos aqui, sem nada para fazer, e vamos representar dois objetos do mundo real em condições de uso típicas do mundo real (é, nada daqueles exemplos esdrúxulos como classe xyz variáveis foo, bar... :P): duas bicicletas.

Uma delas é uma montainbike, e o camarada está se desprendendo do topo de uma montanha qualquer no melhor estilo suicida, o outro cara está em uma bicicleta do tipo de corrida de velocidade, subindo uma ladeira.

Bom vamos ver o que as nossas classes precisam ter para que se represente os objetos reais:

- Tipo;
- Modelo;
- Número de marchas;
- Aro
- Marcha atual;
- Velocidade.

Bem, vamos então a nossa classe Bibicleta:

public class Bicicleta {

    private String tipo;
    private String modelo;
    private int marchas;
    private int aro;
    private int marchaCorrente;
    private static double velocidade;

    public String getTipo() {
        return tipo;
    }

    public void setTipo(String tipo) {
        this.tipo = tipo;
    }

    public int getAro() {
        return aro;
    }

    public void setAro(int aro) {
        this.aro = aro;
    }

    public int getMarchas() {
        return marchas;
    }

    public void setMarchas(int marchas) {
        this.marchas = marchas;
    }

    public String getModelo() {
        return modelo;
    }

    public void setModelo(String modelo) {
        this.modelo = modelo;
    }

    public void setMarchaCorrente(int marchaCorrente) {
        this.marchaCorrente = marchaCorrente;
    }

    public int getMarchaCorrente() {
        return this.marchaCorrente;
    }

    public static void frear() {
        Bicicleta.velocidade--;
    }

    public static void acelerar(int velocidade) {
        Bicicleta.velocidade += velocidade;
    }

    public static double getVelocidade() {
        return Bicicleta.velocidade;
    }

    public Bicicleta() {
    }

    public String toString() {
        String texto = "Tipo: " + this.getTipo() +
                       " Madelo: " + this.getModelo() +
                       " Marchas: " + this.getMarchas() +
                       " Aro: " + this.getAro();

        return texto;
    }

    public Bicicleta(String tipo, String modelo, int marchas, int aro) {
        this.tipo = tipo;
        this.modelo = modelo;
        this.marchas = marchas;
        this.aro = aro;
    }
}

Notem o seguinte, nossa classe tem um campo definido como estático (static), o campo velocidade. Estático na sua definição quer dizer: adj. relativo ao equilíbrio das forças, paralisado, imóvel, firme, em repouso. Paralisado é o mais importante para nós.

Imagine que um campo estático é um cara que uma vez que se cria o objeto e se atribui um valor a ele todas as demais estâncias da nossa classe passam a assumir este valor.

Ou seja criamos uma bicicleta com a nossa classe assim:

Bicicleta b0 = new Bicicleta("Montainbike", "Caloi Aluminum", 21, 26);

Agora vamos configurar alguns estados a ela:

b0.setMarchaCorrente(21);
b0.acelerar(45);

Beleza, o que quer dizer que o cara está na marcha 21 a 45km/h, porém vamos ver o que acontece ao criarmos mais uma bicicleta:

Bicicleta b1 = new Bicicleta("Speed", "Caloi Estrada", 10, 28);
b1.setMarchaCorrente(1);
b1.acelerar(9);

Bom, vejamos o que o método acelerar faz: Bicicleta.velocidade += velocidade; Bicicleta já indica que a coisa não é específica para o objeto que chamou o método (this. indicaria isso). Logo se tínhamos 45km/h atribuído ao primeiro objeto, agora adicionamos 9km/h e compartilhamos para ambos 54kh/h como valor para o campo , e pior os dois objetos estão errados agora. Cheque com o método getVelocidade assim: bo.getVelocidade() e b1.getVelocidade(). O resultado é 54!

Entendeu como os campos estáticos se comportam? Em um programa enquanto eu estiver estanciando Bicicleta todas elas estarão com o campo velocidade apontando para o mesmo valor em memória e sempre que alguma das estâncias modificar este valor todas as demais vão ter este campo alterado.

Simples! Agora adicione o método main abaixo listado na sua classe e execute-o para ver a saídas.

    public static void main(String[] args) {
        //Criando duas bikes de modelos e características diferentes
        Bicicleta b0 = new Bicicleta("Montainbike", "Caloi Aluminum", 21, 26);
        Bicicleta b1 = new Bicicleta("Speed", "Caloi Estrada", 10, 28);

        //Checando as duas após a criação
        System.out.println(b0.toString());
        System.out.println(b1.toString());

        //Configurando a primeira
        b0.setMarchaCorrente(21);
        b0.acelerar(45);

        System.out.println("b0 está a 45km/h"); //Até aqui ok

        //Configurando a segunda
        b1.setMarchaCorrente(1);
        b1.acelerar(9); //Será?

        System.out.println("b1 está a 9km/h"); //Errado! Está a 54!

        b0.frear(); //Errado novamente, ambas as bikes estão freando!

        /*
         * Constatamos que a velocidade dela esteve errada desde o momento da
         * criação da segunda bike, pois ao setarmos a velocidade da segunda
         * somamos a velocidade pretendida para a segunda bike com a que já
         * estava atribuída a primeira! Agora decrementando em 1km/h temos o
         * valor errôneo de 53km/h ao invés dos 44km/h pretendidos com a ação.
         */
        System.out.println("b0 está agora freando, velocida está em " +
                           b0.getVelocidade() + "km/h");

        System.out.println("Bicicleta b0 está na marcha " +
                           b0.getMarchaCorrente() + " a " + b0.velocidade +
                           " km/h");

        System.out.println("Bicicleta b1 está na marcha " +
                           b1.getMarchaCorrente() + " a " + b1.velocidade +
                           " km/h");
    }

Lembrando que métodos podem ser estáticos também. Onde normalmente se tem estância.método para poder invocar um método, métodos estáticos não precisam disto, podem (e devem) ser invocados sem a referência ao objeto invocador. Exemplo disso é em nossa própria classe Bicicleta, em que o método frear e acelerar como manipulam uma variável estática são declarados como estáticos, e estamos fazendo invocações a eles usando b0.acelelar() e b0.frear(). O correto deveria ser direto frear() e acelerar() já que afetará todas os objetos criados. Fica de tema de casa mudar as chamadas :P. Invocando só frear(), por exemplo, sem referência ao objeto fica até mais fácil de se “ver” que afetará todos os objetos.

T+ pessoal, gostou, não gostou, críticas, elogios, erros... estamos sempre aí, só mandar seu comentário (se possível deixa um e-mail para que eu possa lhes responder).


Aqui tem o post em pdf, para facilitar as coisas :P


http://geocities.yahoo.com.br/sadbuttruebr/blog/
posts_pdf/estaticos.pdf

Nenhum comentário: