A diferença entre variáveis de membro estáticas e variáveis de membro não estáticas
Tome o seguinte exemplo como exemplo
pacote cn.galc.test;public class Cat { /** * Variável de membro estático*/ private static int sid = 0; } public void info() { System.out.println("Meu nome é " + nome + ", NÃO." + id); = 100; Gato mimi = novo Gato("mimi");Entenda o processo de execução de todo o programa desenhando diagramas de análise de memória
Ao executar a primeira frase do programa: Cat.sid = 100;, o sid aqui é uma variável de membro estático. A variável estática é armazenada na área de dados (data seg), então primeiro aloque um pequeno espaço sid na área de dados. . Após a execução da sentença, o sid contém um valor de 100.
O diagrama de layout da memória neste momento é o seguinte:
A seguir, o programa executa:
Gato mimi = novo Gato(“mimi”);
Aqui, o método construtor Cat (String name) da classe Cat é chamado. O método construtor é definido da seguinte forma:
Cat (String nome){ this.name = id=sid++ } Ao chamar, primeiro aloque um pequeno pedaço de memória mm na memória da pilha, que contém o endereço do objeto de instância da classe Cat na memória heap mm é o objeto de referência do objeto da classe Cat na memória heap. Este construtor declara uma variável de parâmetro formal do tipo string, então "mimi" é passado para o construtor como um parâmetro real. Como a constante string é alocada e armazenada na área de dados, há um pequeno pedaço extra de memória na área de dados. . Usado para armazenar a string "mimi". A distribuição de memória neste momento é mostrada na figura abaixo:
Ao chamar o construtor, primeiro aloque um pequeno espaço na memória da pilha para o nome do parâmetro formal e, em seguida, passe a string "mimi" como um parâmetro real para o nome. A string também é um tipo de referência, exceto para aqueles quatro e oito. tipos de dados básicos, todos os outros são tipos de referência, portanto pode-se considerar que uma string também é um objeto. Então isso equivale a passar a referência do objeto "mimi" para name, então agora name aponta para "mimi". Portanto, o layout da memória neste momento é mostrado abaixo:
A seguir, execute o código no corpo do construtor:
este.nome=nome;
Isso aqui se refere ao objeto atual, que se refere ao gato na memória heap. Aqui, o valor contido no nome na pilha é passado para o atributo name do objeto cat na memória heap, portanto neste momento o valor contido no nome também pode ser encontrado no objeto string "mimi" localizado no área de dados. Neste momento, este nome também é um objeto de referência do objeto string "mimi". Através de seu valor de atributo, o objeto string "mimi" localizado na área de dados pode ser encontrado. A distribuição de memória neste momento é mostrada na figura abaixo:
A seguir, execute outra linha de código no corpo do método:
id=sid++;
Aqui, o valor de sid é passado para id, então o valor de id é 100. Depois que o sid é passado, adicione 1. Neste momento, sid se torna 101. O layout da memória neste momento é mostrado na figura abaixo.
Neste ponto, o método construtor é chamado, e todo o espaço de memória ocupado pelas variáveis locais alocadas para este método construtor desaparecerá, portanto a memória de nomes localizada no espaço de pilha desaparecerá. A referência ao objeto string "mimi" na área de dados da memória stack também desaparece. Neste momento, apenas a referência ao objeto string "mimi" na memória heap permanece. O layout da memória neste momento é mostrado abaixo:
Em seguida, execute:
Gato pipi = novo Gato("pipi"); Aqui está a segunda chamada para o método construtor Cat(). Todo o processo de chamada é igual à primeira vez. Após a conclusão da chamada, o layout da memória neste momento é mostrado na figura abaixo:
As duas últimas linhas de código são impressas chamando o método info(). Os resultados da impressão são os seguintes:
Através deste programa, podemos ver o papel desta variável de membro estático sid, que pode ser contada. Sempre que surgir um gato novo, dê um número a ele. Deixe-o adicionar 1 sozinho.
Após a execução do programa, todo o layout na memória ficará conforme mostrado na figura acima. Continua até o momento anterior à conclusão da chamada do método principal.
Aqui, o método construtor Cat(String name) é chamado para criar dois gatos. Primeiro, dois pequenos espaços, mimi e pipi, são alocados na memória da pilha, que contém os endereços onde os dois gatos podem ser encontrados. para os endereços na memória heap. Duas aspas de gato. O método de construção aqui declara uma variável do tipo string. A constante string é alocada na área de dados, portanto as strings passadas mimi e pipi serão armazenadas na área de dados. Portanto, a área de dados possui dois pequenos blocos de memória para armazenar as strings mimi e pipi, que contêm as strings "mimi" e "pipi". Strings também são tipos de referência. Todos os tipos de dados são tipos de referência. Então você pode pensar em uma string como um objeto.
Aqui estão dois novos gatos. Ambos os gatos têm seus próprios atributos de id e nome, portanto, o id e o nome aqui são variáveis de membro não estáticas, ou seja, não há modificação estática. Portanto, toda vez que um novo gato é criado, esse novo gato tem seu próprio id e nome, ou seja, as variáveis-membro não estáticas id e nome possuem cópias separadas para cada objeto. Mas para variáveis de membro estático, há apenas uma cópia. Não importa quantos objetos sejam novos, mesmo que não haja novos objetos, as variáveis de membro estático reterão uma cópia na área de dados. Assim como o sid aqui, o sid é armazenado na área de dados. Não importa quantos gatos novos estejam na memória heap, há apenas uma cópia do sid e apenas uma cópia é mantida na área de dados.
Variáveis de membro estático pertencem à classe inteira, não pertencem a um objeto específico. Então, como acessar o valor dessa variável de membro estático? Em primeiro lugar, qualquer objeto pode acessar esse valor estático e, ao acessar, acessa a mesma memória. O segundo ponto é que você pode acessar esse valor estático mesmo se não houver nenhum objeto. Você pode acessar esse valor estático por meio de "nome da classe.nome da variável de membro estático", portanto, no futuro, você verá um determinado nome de classe mais "." seguido por Se houver uma coisa, então a seguinte deve ser estática, como "System.out". Aqui, esta saída é acessada através do nome da classe (classe do sistema) mais ".", então esta saída deve ser estática.
Se um membro da classe for declarado estático, ele poderá ser acessado antes de qualquer objeto da classe ser criado, sem a necessidade de fazer referência a nenhum objeto. O exemplo mais comum de membro estático é main(). Como main() deve ser chamado quando o programa inicia a execução, ele é declarado estático.
Variáveis declaradas estáticas são essencialmente variáveis globais. Quando um objeto é declarado, uma cópia da variável estática não é gerada, mas todas as variáveis de instância da classe compartilham a mesma variável estática. Por exemplo: declare uma contagem de variável estática como a contagem de novas instâncias de classe. Os métodos declarados estáticos têm as seguintes restrições:
(1). Eles só podem chamar outros métodos estáticos.
(2) Eles só podem acessar dados estáticos.
(3). Eles não podem fazer referência a this ou super de forma alguma.
Se precisar inicializar suas variáveis estáticas por meio de cálculo, você pode declarar um bloco estático. O bloco estático é executado apenas uma vez quando a classe é carregada. O exemplo abaixo mostra
A classe possui um método estático, algumas variáveis estáticas e um bloco de inicialização estático: public class UserStatic { static int a = 3; x); System.out.println("a = " + a); System.out.println("b = " + b); inicializado."); b = a * 4; } public static void main(String args[]) { meth(42); } } Depois que a classe UseStatic é carregada, todas as instruções estáticas são executadas. Primeiro, a é definido como 3, depois o bloco estático é executado (imprimindo uma mensagem) e, finalmente, b é inicializado como a*4 ou 12. Então main() é chamado, main() chama meth(), passando o valor 42 para x. As três instruções println() referem-se a duas variáveis estáticas aeb e à variável local x.
Nota: É ilegal fazer referência a quaisquer variáveis de instância em um método estático.
Aqui está o resultado deste programa:
Bloco estático inicializado x = 42 a = 3 b = 12.
Métodos e variáveis estáticos podem ser usados independentemente de qualquer objeto fora da classe na qual estão definidos. Neste caso, você só precisa adicionar o operador ponto (.) após o nome da classe. Por exemplo, se desejar chamar um método estático de fora da classe, você pode usar o seguinte formato geral:
nome da classe.método()
Aqui, classname é o nome da classe na qual o método estático é definido. Como você pode ver, esse formato é semelhante ao formato de chamada de métodos não estáticos por meio de variáveis de referência de objeto. Uma variável estática pode ser acessada no mesmo formato – o nome da classe mais o operador ponto. É assim que Java implementa uma versão controlada de funções e variáveis globais.
Resumir:
(1) Membros estáticos não podem ser acessados por instâncias criadas pela classe na qual estão localizados.
(2) Se os membros sem modificação estática forem membros do objeto, eles serão propriedade de cada objeto.
(3) Membros modificados com static são membros de classe, que podem ser chamados diretamente por uma classe e são comuns a todos os objetos.
Java Estático: Como modificador, pode ser usado para modificar variáveis, métodos e blocos de código (mas não deve modificar classes).
(1) Modificar variáveis:
Uma propriedade compartilhada por todos os objetos de uma classe, também chamada de variável de classe. Isso é semelhante às variáveis globais na linguagem C. Variáveis de classe são inicializadas quando a classe é carregada e inicializadas apenas uma vez. Quando qualquer objeto no programa modifica uma variável estática, outros objetos verão o valor modificado. Portanto, variáveis de classe podem ser usadas como contadores. Além disso, as variáveis Java Static podem ser acessadas diretamente usando o nome da classe sem a necessidade de um objeto.
(2) Método de modificação:
Uma função comum a todos os objetos de uma classe é chamada de método estático. Os métodos estáticos também podem ser acessados diretamente usando o nome da classe, sem a necessidade de um objeto. Portanto, variáveis não estáticas e métodos não estáticos não podem ser acessados diretamente em métodos estáticos, e palavras-chave como this ou super não podem aparecer em métodos estáticos.
(3) Modifique os blocos de código Java:
Use static para modificar um bloco de código independente em uma classe, que é chamado de bloco de código estático. Os blocos de código estático são executados quando a classe é carregada pela primeira vez e apenas uma vez. Os blocos de código estático não têm nomes, portanto não podem ser chamados explicitamente, mas só são chamados pela máquina virtual quando a classe é carregada. É usado principalmente para concluir algumas operações de inicialização.
(4) Vamos falar sobre carregamento de classe:
Quando a JVM usa uma classe pela primeira vez, ela irá até o caminho especificado pelo caminho de classe para encontrar o arquivo de bytecode correspondente à classe, lê-lo na JVM e salvá-lo. Este processo é chamado de carregamento de classe.
Percebe-se que seja uma variável, método ou bloco de código, desde que modificado com estático, estará "pronto" quando a classe for carregada, ou seja, pode ser utilizada ou já foi executada. Todos podem ser executados sem objetos. Pelo contrário, se não houver estática, ela deverá ser acessada através do objeto.