O que a palavra-chave 'estática' faz em uma classe?

444

Para ser específico, eu estava tentando este código:

package hello;

public class Hello {

    Clock clock = new Clock();

    public static void main(String args[]) {
        clock.sayTime();
    }
}

Mas deu o erro

Não é possível acessar o campo não estático no método estático principal

Então eu mudei a declaração de clockpara isso:

static Clock clock = new Clock();

E funcionou. O que significa colocar essa palavra-chave antes da declaração? O que exatamente ele fará e / ou restringirá em termos do que pode ser feito com esse objeto?

Click Voto a favor
fonte
Mais uma vez, lembre-se de que há uma instância de estática por classe por CLASSLOADER.
Javamann 5/01/09

Respostas:

633

static membros pertencem à classe em vez de uma instância específica.

Isso significa que existe apenas uma instância de um staticcampo [1], mesmo que você crie um milhão de instâncias da classe ou não crie nenhuma. Será compartilhado por todas as instâncias.

Como os staticmétodos também não pertencem a uma instância específica, eles não podem se referir aos membros da instância. No exemplo dado, mainnão sabe a qual instância da Helloclasse (e, portanto, a qual instância da Clockclasse) ela deve se referir. staticmembros podem se referir apenas a staticmembros. Os membros da instância podem, é claro, acessar staticmembros.

Nota lateral: Obviamente, os staticmembros podem acessar os membros da instância por meio de uma referência a objeto .

Exemplo:

public class Example {
    private static boolean staticField;
    private boolean instanceField;
    public static void main(String[] args) {
        // a static method can access static fields
        staticField = true;

        // a static method can access instance fields through an object reference
        Example instance = new Example();
        instance.instanceField = true;
    }

[1]: Dependendo das características do tempo de execução, ele pode ser um por ClassLoader ou AppDomain ou thread, mas isso não vem ao caso.

Mehrdad Afshari
fonte
5
No .NET, você também pode modificar esse comportamento usando o atributo [ThreadStatic] - que torna o local estático para segmentos específicos.
TheSoftwareJedi 5/01/09
4
Eu sei que esse post é antigo, mas para iniciantes como eu, isso pode ser útil. stackoverflow.com/questions/7026507/…
user3526905
Você não conseguiria acessar instance.instanceField porque é um var privado? Ou é válido porque você instancia o objeto dentro de sua própria classe? Parece um pesadelo recursivo para mim, mas eu sou um novato em Java.
Matt Corby
Se o membro estático de uma classe é referenciado por 2 threads diferentes, quantas instâncias existem desse membro estático? Eu sinto que é 2, mas se você quiser a mesma instância entre threads, a palavra-chave volátil deve ser usada. Isso está correto?
Dan
..e o valor é preservado se não houver instâncias da classe restantes?
Mckenzm 05/08/19
130

Isso significa que há apenas uma instância de "clock" no Hello, não uma por cada instância separada da classe "Hello", ou mais, significa que haverá uma referência de "clock" comumente compartilhada entre todas as instâncias de a classe "Olá".

Portanto, se você fizesse um "novo Olá" em qualquer lugar do seu código: A- no primeiro cenário (antes da alteração, sem usar "estático"), ele criaria um novo relógio toda vez que um "novo Olá" fosse chamado, mas B- no segundo cenário (após a alteração, usando "estático"), cada instância "nova Hello" ainda compartilharia e usaria a referência inicial e o mesmo "clock" criado pela primeira vez.

A menos que você precise de "relógio" em algum lugar fora do main, isso também funcionaria:

package hello;
public class Hello
{
    public static void main(String args[])
    {
      Clock clock=new Clock();
      clock.sayTime();    
    }
}
Paul Tomblin
fonte
Essa é a maneira mais comum de fazer isso. A main()rotina deve ser independente.
21477 Jason S
1
No segundo caso, ele criaria uma nova instância do Clock toda vez que o método principal for chamado, certo?
Click Upvote
2
Na segunda instância, relógio estático, ele o criaria apenas uma vez. No meu exemplo, onde o relógio está dentro do main, então sim, ele seria criado sempre que main é chamado. Mas normalmente main é chamado apenas uma vez no início do programa e, quando sai, tudo é liberado.
Paul Tomblin
Não consigo entender como é possível criar um novo relógio no método principal? como você diz que o criaria sempre que main for chamado, mas existe apenas um método principal. como esse método principal pode se referir a diferentes instâncias de relógio? É um pouco difícil entender como é possível criar uma nova instância de clock no main e usar seu método sayTime (), mas não é possível tornar a instância fora do main e usar sayTime (). como é tudo de graça quando main é chamado uma vez? @PaulTomblin
ShakibaZar
@ user5621266 Eu usei o mainmétodo apenas porque o OP o fez. Se, em vez disso, fosse um método público chamado de outro lugar e a classe Hello fosse instanciada mais de uma vez, ela poderia criar uma instância Clock para cada instância Hello, a menos que clockfosse estático.
Paul Tomblin
97

A staticpalavra-chave significa que algo (um campo, método ou classe aninhada) está relacionado ao tipo e não a uma instância específica do tipo. Por exemplo, alguém chama Math.sin(...)sem nenhuma instância da Mathclasse e, de fato, você não pode criar uma instância da Mathclasse.

Para obter mais informações, consulte o bit relevante do Java Tutorial da Oracle .


Nota

Infelizmente, o Java permite acessar membros estáticos como se fossem membros da instância, por exemplo

// Bad code!
Thread.currentThread().sleep(5000);
someOtherThread.sleep(5000);

Isso torna olhar como se sleepé um método de instância, mas na verdade é um método estático - ele sempre faz com que o sono thread atual. É uma prática recomendada deixar isso claro no código de chamada:

// Clearer
Thread.sleep(5000);
Jon Skeet
fonte
1
Outro exemplo: System.out.println () parece um método de classe, mas na verdade é um método de instância. Desde out é uma instância PrintStream na classe System.
Jiahui Zhang
@LeslieCheung: Não, não parece um método de classe para mim, assim System.outcomo um nome de tipo para mim.
precisa
42

A staticpalavra-chave em Java significa que a variável ou função é compartilhada entre todas as instâncias dessa classe, pois pertence ao tipo , não aos objetos reais.

Portanto, se você possui uma variável: private static int i = 0;e você a incrementa ( i++) em uma instância, a alteração será refletida em todas as instâncias. iagora será 1 em todas as instâncias.

Métodos estáticos podem ser usados ​​sem instanciar um objeto.

geowa4
fonte
4
"Compartilhada entre todas as instâncias" dá a impressão errada, IMO - ele sugere que você faça necessidade de ter uma instância do objeto.
911 Jon Skeet
1
(Considerando realmente lá não precisa ser nenhum dos casos, porque o campo estático etc pertence ao tipo .)
Jon Skeet
@ Jon Skeet estático pertence ao tipo, não ao objeto? Você pode contar mais detalhes? Digite como tipo de dados: int, double, ...?
Truongnm
@truongnm: Digite como na classe que declara a variável / método.
precisa
26

Uso básico de membros estáticos ...

public class Hello
{
    // value / method
    public static String staticValue;
    public String nonStaticValue;
}

class A
{
    Hello hello = new Hello();
    hello.staticValue = "abc";
    hello.nonStaticValue = "xyz";
}

class B
{
    Hello hello2 = new Hello(); // here staticValue = "abc"
    hello2.staticValue; // will have value of "abc"
    hello2.nonStaticValue; // will have value of null
}

É assim que você pode ter valores compartilhados em todos os membros da classe sem enviar a instância da classe Hello para outra classe. E com estática, você não precisa criar uma instância de classe.

Hello hello = new Hello();
hello.staticValue = "abc";

Você pode chamar valores ou métodos estáticos pelo nome da classe:

Hello.staticValue = "abc";
Vasil Valchev
fonte
22

Estático significa que você não precisa criar uma instância da classe para usar os métodos ou variáveis ​​associadas à classe. No seu exemplo, você pode chamar:

Hello.main(new String[]()) //main(...) is declared as a static function in the Hello class

diretamente, em vez de:

Hello h = new Hello();
h.main(new String[]()); //main(...) is a non-static function linked with the "h" variable

De dentro de um método estático (que pertence a uma classe), você não pode acessar nenhum membro que não seja estático, pois seus valores dependem da instanciação da classe. Um objeto Clock não estático, que é um membro da instância, teria um valor / referência diferente para cada instância da sua classe Hello e, portanto, você não poderia acessá-lo a partir da parte estática da classe.

Elie
fonte
Grande explicação para o contexto estático :)
Abdel-Raouf
20

Estático em Java:

Static é um modificador sem acesso. A palavra-chave estática pertence à classe e não à instância da classe. pode ser usado para anexar uma variável ou método a uma classe.

A palavra-chave estática PODE ser usada com:

Método

Variável

Classe aninhada dentro de outra Classe

Bloco de Inicialização

NÃO PODE ser usado com:

Classe (não aninhada)

Construtor

Interfaces

Método Classe interna local (diferença e classe aninhada)

Métodos de classe interna

Variáveis ​​de instância

Variáveis ​​locais

Exemplo:

Imagine o exemplo a seguir, que possui uma variável de instância denominada count, que é incrementada no construtor:

package pkg;

class StaticExample {
    int count = 0;// will get memory when instance is created

    StaticExample() {
        count++;
        System.out.println(count);
    }

    public static void main(String args[]) {

        StaticExample c1 = new StaticExample();
        StaticExample c2 = new StaticExample();
        StaticExample c3 = new StaticExample();

    }
}

Resultado:

1 1 1

Como a variável de instância obtém a memória no momento da criação do objeto, cada objeto terá a cópia da variável de instância; se for incrementada, ela não será refletida em outros objetos.

Agora, se alterarmos a contagem de variáveis ​​de instância para estática , o programa produzirá uma saída diferente:

package pkg;

class StaticExample {
    static int count = 0;// will get memory when instance is created

    StaticExample() {
        count++;
        System.out.println(count);
    }

    public static void main(String args[]) {

        StaticExample c1 = new StaticExample();
        StaticExample c2 = new StaticExample();
        StaticExample c3 = new StaticExample();

    }
}

Resultado:

1 2 3

Nesse caso, a variável estática obterá a memória apenas uma vez; se algum objeto alterar o valor da variável estática, ele manterá seu valor.

Estática com final:

A variável global que é declarada como final e estática permanece inalterada para toda a execução. Porque, os membros estáticos são armazenados na memória da classe e são carregados apenas uma vez em toda a execução. Eles são comuns a todos os objetos da classe. Se você declarar variáveis ​​estáticas como finais, nenhum dos objetos poderá alterar seu valor, pois é final. Portanto, variáveis ​​declaradas como final e estática são algumas vezes chamadas de constantes. Todos os campos das interfaces são referidos como constantes, porque são finais e estáticos por padrão.

insira a descrição da imagem aqui

Recurso de imagem: Estática final

Affy
fonte
15

Para adicionar às respostas existentes, deixe-me tentar com uma imagem:

Uma taxa de juros de 2% é aplicada a TODAS as contas de poupança. Portanto, é estático .

Um equilíbrio deve ser indivíduo , por isso é não estática.

insira a descrição da imagem aqui

Andrejs
fonte
13

Até agora, essa discussão ignorou as considerações sobre o carregador de classes. A rigor, os campos estáticos Java são compartilhados entre todas as instâncias de uma classe para um determinado carregador de classes .

Julien Chastang
fonte
1
Isso foi mencionado por Apocalisp nos comentários sobre a resposta de Merhdad.
Zach Langley
1
Bom ponto. Muitas pessoas não sabem disso, mas quando você começa a mexer com os carregadores de classe, isso se torna muito importante.
Sleske #
2
Tudo isso é verdade, mas não responde à pergunta. Deveria ter sido publicado como um comentário.
Marquês de Lorne #
7

Um campo pode ser atribuído à classe ou a uma instância de uma classe. Por padrão, os campos são variáveis ​​de instância. O uso staticdo campo se torna uma variável de classe, portanto, existe um e apenas um clock. Se você fizer alterações em um lugar, é visível em qualquer lugar. Variáveis ​​de instância são alteradas independentemente uma da outra.

esplêndido
fonte
6

A palavra static- chave é usada para indicar um campo ou método como pertencente à própria classe e não à instância. Usando seu código, se o objeto Clockfor estático, todas as instâncias da Helloclasse compartilharão esse Clockmembro de dados (campo) em comum. Se você o tornar não estático, cada instância individual de Hellopoderá ter um Clockcampo exclusivo .

O problema é que você adicionou um método principal à sua classe Hellopara poder executar o código. O problema aqui é que o método principal é estático e, como tal, não pode se referir a campos ou métodos não estáticos dentro dele. Você pode resolver isso de duas maneiras:

  1. Torne Helloestáticos todos os campos e métodos da classe para que possam ser referidos dentro do método principal . Isso realmente não é uma coisa boa a se fazer (ou a razão errada para tornar um campo e / ou um método estático)
  2. Crie uma instância da sua Helloclasse dentro do método principal e acesse todos os seus campos e métodos da maneira como eles foram planejados.

Para você, isso significa a seguinte alteração no seu código:

package hello;

public class Hello {

    private Clock clock = new Clock();

    public Clock getClock() {
        return clock;
    }

    public static void main(String args[]) {
        Hello hello = new Hello();
        hello.getClock().sayTime();
    }
}
hfontanez
fonte
6

Em Java, a staticpalavra - chave pode ser simplesmente considerada como indicando o seguinte:

"sem consideração ou relação com qualquer instância em particular"

Se você pensar staticdessa maneira, fica mais fácil entender seu uso nos vários contextos em que é encontrado:

  • Um staticcampo é um campo que pertence à classe e não a qualquer instância específica

  • Um staticmétodo é um método que não tem noção de this; é definido na classe e não conhece nenhuma instância específica dessa classe, a menos que uma referência seja passada a ela

  • Uma staticclasse membro é uma classe aninhada sem nenhuma noção ou conhecimento de uma instância de sua classe envolvente (a menos que uma referência a uma instância de classe envolvente seja passada a ela)

scottb
fonte
5

Static torna o membro do relógio um membro da classe em vez de um membro da instância. Sem a palavra-chave estática, você precisaria criar uma instância da classe Hello (que possui uma variável de membro do clock) - por exemplo

Hello hello = new Hello();
hello.clock.sayTime();
Stephen Doyle
fonte
5

métodos estáticos não usam variáveis ​​de instância da classe em que estão definidos. Uma explicação muito boa da diferença pode ser encontrada nesta página

Marc Novakowski
fonte
5

Eu desenvolvi um gosto por métodos estáticos (somente, se possível) nas classes "auxiliares".

A classe de chamada não precisa criar outra variável de membro (instância) da classe auxiliar. Você acabou de chamar os métodos da classe auxiliar. Também a classe auxiliar foi aprimorada porque você não precisa mais de um construtor e não precisa de variáveis ​​de membro (instância).

Provavelmente existem outras vantagens.

javaguy
fonte
4
//Here is an example 

public class StaticClass 
{
    static int version;
    public void printVersion() {
         System.out.println(version);
    }
}

public class MainClass 
{
    public static void main(String args[]) {  
        StaticClass staticVar1 = new StaticClass();
        staticVar1.version = 10;
        staticVar1.printVersion() // Output 10

        StaticClass staticVar2 = new StaticClass();
        staticVar2.printVersion() // Output 10
        staticVar2.version = 20;
        staticVar2.printVersion() // Output 20
        staticVar1.printVersion() // Output 20
    }
}
Mohammad Parvez
fonte
3

Também pode pensar em membros estáticos que não possuem um ponteiro "this". Eles são compartilhados entre todas as instâncias.

kal
fonte
3

Noções básicas sobre conceitos estáticos

public class StaticPractise1 {
    public static void main(String[] args) {
        StaticPractise2 staticPractise2 = new StaticPractise2();
        staticPractise2.printUddhav(); //true
        StaticPractise2.printUddhav(); /* false, because printUddhav() is although inside StaticPractise2, but it is where exactly depends on PC program counter on runtime. */

        StaticPractise2.printUddhavsStatic1(); //true
        staticPractise2.printUddhavsStatic1(); /*false, because, when staticPractise2 is blueprinted, it tracks everything other than static  things and it organizes in its own heap. So, class static methods, object can't reference */

    }
}

Segunda classe

public class StaticPractise2 {
    public static void printUddhavsStatic1() {
        System.out.println("Uddhav");
    }

    public void printUddhav() {
        System.out.println("Uddhav");
    }
}
Uddhav Gautam
fonte
2

main() é um método estático que possui duas restrições fundamentais:

  1. O método estático não pode usar um membro de dados não estáticos ou chamar diretamente o método não estático.
  2. this()e super()não pode ser usado em contexto estático.

    class A {  
        int a = 40; //non static
        public static void main(String args[]) {  
            System.out.println(a);  
        }  
    }

Saída: erro de tempo de compilação

Bharthan
fonte
1

Variáveis ​​estáticas Só podem ser acessadas em métodos estáticos; portanto, quando declaramos as variáveis ​​estáticas, esses métodos getter e setter serão métodos estáticos

métodos estáticos é um nível de classe que podemos acessar usando o nome da classe

A seguir, exemplo de Getters e Setters de variáveis ​​estáticas:

public class Static 
{

    private static String owner;
    private static int rent;
    private String car;
    public String getCar() {
        return car;
    }
    public void setCar(String car) {
        this.car = car;
    }
    public static int getRent() {
        return rent;
    }
    public static void setRent(int rent) {
        Static.rent = rent;
    }
    public static String getOwner() {
        return owner;
    }

    public static void setOwner(String owner) {
        Static.owner = owner;
    }

}
Bala Krishna
fonte
1

Uma pergunta foi feita aqui sobre a escolha da palavra 'estático' para esse conceito. Foi enganado por essa pergunta, mas não acho que a etimologia tenha sido claramente abordada. Assim...


É devido à reutilização de palavras-chave, começando com C.

Considere declarações de dados em C (dentro de um corpo de função):

    void f() {
        int foo = 1;
        static int bar = 2;
         :
    }

A variável foo é criada na pilha quando a função é inserida (e destruída quando a função termina). Por outro lado, o bar está sempre lá, então é 'estático' no sentido do inglês comum - não vai a lugar nenhum.

Java e linguagens semelhantes têm o mesmo conceito para dados. Os dados podem ser alocados por instância da classe (por objeto) ou uma vez para toda a classe. Como o Java pretende ter uma sintaxe familiar para programadores de C / C ++, a palavra-chave 'estática' é apropriada aqui.

    class C {
        int foo = 1;
        static int bar = 2;
         :
    }

Por fim, chegamos aos métodos.

    class C {
        int foo() { ... }
        static int bar() { ... }
         :
    }

Conceitualmente, existe uma instância de foo () para todas as instâncias da classe C. Há apenas uma instância de bar () para toda a classe C. Isso é paralelo ao caso que discutimos para dados e, portanto, usando 'static 'é novamente uma escolha sensata, especialmente se você não deseja adicionar mais palavras-chave reservadas ao seu idioma.

user13068046
fonte