Entendendo static

Assunto: Você se sente confuso quanto à utilidade da palavra-chave static? Não sabe quando nem como usar? Seus problemas acabaram, leia este tutorial aqui do GUJ e acabe com suas dúvidas.

Você pode ler este artigo na íntegra em http://www.guj.com.br/java.artigo.121.1.guj

Por favor, coloque os seus comentários sobre este artigo aqui.

Adorei o seu artigo. Muito claro e direto!

Entretanto gostaria de saber de você se já esteve em alguma situação onde determinados métodos precisavam existir, mas simplesmente não se encaixavam em nenhuma classe da aplicação. E como você resolveu o problema? Que técnicas ou design patterns teve de usar ou “quebrar”?

Abraços.

Um método static realmente se parece com uma funcao
Cabe a voce a decisao de onde ele deve ficar. Pois voce pode mudar muito bem onde o metodo estatico esta para outra classe, sem maiores problemas.

A SUN criou a classe Math para ter os metodos estaticos que abordam o mesmo assunto. Voce vai ver por ai muita gente ter uma classe que chama “MeuProjetoUtils” contendo uma serie de cosntantes e metodos estaticos. Apesar de eu tambem usar isso, creio que a melhor solucao seja ter classes que possuem metodos estaticos e nao estaticos. Assim como a aclasse Integer têm.

Muito bom o artigo sobre static…uma vez estava desenvolvendo um projeto em java e apanhei muito ocm variaveis estaticas…deu muito pau no meu programa e eu nao sabia pq, depois fui descobrir que eram variaveis estaticas do programa.

ate mais…

:smiley: Gostaria de deixar a minha dica aqui sobre o assunto. Bem, se uma classe generica possui um dado statico… cujo valor 1… Todas as classe que a utilizarem (a classe generica) possuiram o valor 1 do dado. Agora se alterarmos na classe generica o valor do dado p/ por exemplo 2, todas as classe q utilizam ( a classe generica ) teram o valor 2. Um exemplo p/ ficar mais claro da logica… Eh soh imaginarmos o jogo pac-man… Por que todos os fantasminhas (objetos) fogem quando o comecome (objeto) se alimenta das frutas? :wink: Ai estah um exemplo na pratica do uso de static.
Gostei do artigo…
PJ2002.

Exatamente. Como soh existe uma unica referencia na memoria, caso alguem altere o valor, o efeito sera global. Uma saida para garantir a seguranca, caso o valor nao possa ser alterado de maneira alguma, eh simplesmente declarar como “final” tambem.

Rafael

Lá vai mais algumas dicas:

– Métodos estáticos nunca são VIRTUAIS, e não podem ser sobreescritos (Overriding) em suas subclasses! Isso explica a impossibilidade de usar Polimorfismo, onde qualquer referência é resolvida através de early binding!

– Static são úteis para membros, seja uma variavel ou metodo, que não depende da instância de uma classe, isto é, quando não existe nenhum vínculo/dependencia com o estado de um objeto.

– membros statics são corregados em memória assim que o programa é executado.

– Ah, uma outra coisa interessante… o metodo entry point main() precisa ser static justamente pq a VM nao cria nenhuma instancia de sua classe.

Espero ter contribuído!

Gerson K.

Eu nao sei exatamente como definir, mas é possivel sobrescrever um metodo static:

class Pai
{
	public static void escreve()
	{
		System.out.println("Pai");
	}
}

class Filho extends Pai
{
	public static void escreve()
	{
		System.out.println("Filho");
	}
}

public class OverrideStatic
{
	public static void main(String args[])
	{
		Pai p = new Pai();
		p.escreve();
		
		Filho f = new Filho();
		f.escreve();
		
		Pai p2 = new Filho();
		p2.escreve();
	}
}

Resultado:

Pai
Filho
Pai

Note que, ao contrario de um metodo normal, chamar

p2.escreve();

chama o metodo da classe Pai, ao contrario da classe Filho, o que eh a acao a acontecer em um metodo “normal”. A especificacao diz que metodos static sao explicitamente “final”, tanto que se voce remover a palavra-chave “static” da classe Filho, um erro de compilacao ira ocorrer. Mas com a assinatura igual, funciona.

Rafael

Rafael,

Não dá pra sobreescrever um método estatico não. O que acontece é que existe uma sobreposição de método, onde um deles fica oculto.

O método “p2.escreve()” chamou o método da classe pai justamente pq um método estático não é virtual, diferentemente dos métodos non-static, que por padrão, são implicitamente virtuais (diferentemente de C++). Não sei se está claro esse conceito… Se não, procure por “Virtual Function”.

Não lembro onde exatamente lí isso… Mas, de qquer forma, é só dar uma olhada no proprio tutorial da sun.

"Also, a subclass cannot override methods that are declared static in the superclass. In other words, a subclass cannot override a class method. A subclass can hide a static method in the superclass by declaring a static method in the subclass with the same signature as the static method in the superclass. "

http://java.sun.com/docs/books/tutorial/java/javaOO/override.html

Espero ter contribuído!

Gerson K.

gerson e rafael, voces estao falando a mesma coisa

metodos statics nao podem ser reescritos, apenas hidden (pensem e faz todo sentido do mundo isso acontecer)

outra coisa. eh mais facil lembrar eh o seguinte: o unico lugar em que ocorre chamada de metodo virtual sao em metodos de instancia. de todos os outros jeitos, a resolucao ocorre em TEMPO DE COMPILACAO

entao se PAI e FILHO tiverem um public int x, e voce fizer

Pai p = new Filho();
imprime(p.x);

vai sair a variavel do Pai mesmo, e nao do filho, pq existem DUAS. a do filho apenas escondeu a do pai em determinadas situacoes

Geron. membros estaticos NAO sao carregados quando o programa executa. Eles sao carregados quando o ClassLoader le a classe X, e se esse X tiver membros etaticos, eles sao carregados.

Mas se você fizer Pai p = new Filho(); System.out.println(p.x); Vai imprimir o x do pai de qualquer maneira. Dinamic binding só ocorre com métodos.

Sim, eu li a JLS depois que tinha postado a minha msg, pois tava vendo uns lance com protected tambem, e la falava do hidding e tal.

Rafael

exatamente, eh o que eu e o gerson falamos acima!

Pessoal,

Outro dia estava lendo um ótimo tutorial no JavaRanch, How my Dog learned Polymorphism e lá diz que Java sempre faz late-binding. Por exemplo, se eu executar…

Animal d = new Dog(); d.play();

…o método [color=“blue”]play()[/color] chamado será da classe [color=“blue”]Dog[/color], e não da classe [color=“blue”]Animal[/color].

Late-binding, então, ocorre apenas para métodos, e não para variáveis?

[quote=“Rob Fleming”]Pessoal,
Late-binding, então, ocorre apenas para métodos, e não para variáveis?[/quote]

exato
associacao de atributos sao resolvidos em tempo de compilacao (early binding), metodos nao estaticos sao resolvidos em tempo de execucao (virtual method invocation, melhor q “late binding”)

Saquei :slight_smile: . Valeu! :smiley:

Olá pessoal,

Quero dizer que adorei o artigo, muito bom mesmo excelente consegui entender pelo menos basicamente o que rola com o método static, que inclusive a Sun adora pedir na prova de cerificação né!!

Gostaria de saber se vocês teriam em mente os mesmos artigos só que falando a fundo do private e do protected, essas são minhas grandes dúvidas;

Estou fazendo o SL110, e o SL275 da SUN, e tentarei a prova de certificação. O SL110 é muito fraquinho, nem cobre a fundo a questão dos modificadores. Acho muito interessante artigos como este.

Espero que o SL275 cubra :o)

Obrigado pessoal!!!

Sobre modificadores de acesso não existem grandes segredos e peculiaridades, mas já escrevi um artigo a respeito, que encontra-se no seguinte endereço:
http://www.portaljava.com/home/modules.php?name=Sections&op=viewarticle&artid=19

Estava lendo mais atentamente o artigo e percebi um equívoco no primeiro exemplo completo, o do “contador”. Na verdade a variável "contador é zerada no construtor, assim como a variável “outroContador”, só que, como todos os objetos são criados sucessivamente ele não demostra sua real funcionalidade. Se fosse implemetada desta fora:

public class TesteStatic
{
    public static void main(String args[])
    {
        Classe1 c1 = new Classe1();

        c1.incrementaContador();
        c1.incrementaOutroContador();

        Classe1 c2 = new Classe1();

        c2.incrementaContador();
        c2.incrementaOutroContador();

        Classe1 c3 = new Classe1();

        c3.incrementaContador();
        c3.incrementaOutroContador();

        Classe1 c4 = new Classe1();

        c4.incrementaContador();
        c4.incrementaOutroContador();
    }
}

… o resultado seria o seguinte:
contador agora é 1
outroContador agora é 1
contador agora é 1
outroContador agora é 1
contador agora é 1
outroContador agora é 1
contador agora é 1
outroContador agora é 1

Então por que do resultado obtido é correto no formato original do artigo? Porque quando criado cada instância de “Classe1”, ele cria uma cópia para cada objeto de “outroContador” na memória, mas isso não acontece para “contador”, que existe apenas uma cópia na memória para todas as instância e inclusive para a própria classe “Classe1”.
O artigo é muito interessante e me valeu de muitas informações que eu não dispunha, e se alguém encontrar mais algum equívoco no que escrevi, ficaria grato de ser corrigido.
Valeu galera

Ok, vc esta certo. Atualizei ja o tutorial para corrigir esse problema. Valeu.

Rafael