Aqui está o meu código:
class A {
static A obj = new A();
static int num1;
static int num2=0;
private A() {
num1++;
num2++;
}
public static A getInstance() {
return obj;
}
}
public class Main{
public static void main(String[] arg) {
A obj = A.getInstance();
System.out.println(obj.num1);
System.out.println(obj.num2);
}
}
A saída é 1 0
, mas não consigo entender.
Alguém pode me explicar?
Respostas:
Em Java ocorrem duas fases: 1. Identificação, 2. Execução
Em identificação fase de , todas as variáveis estáticas são detectadas e inicializadas com valores padrão.
Então agora os valores são:
A obj=null
num1=0
num2=0
A segunda fase, execução , começa de cima para baixo. Em Java, a execução começa a partir dos primeiros membros estáticos.
Aqui é sua primeira variável estática
static A obj = new A();
, portanto, primeiro ela criará o objeto dessa variável e chamará o construtor, daí o valor denum1
enum2
se torna1
.E então, novamente,
static int num2=0;
será executado, o que tornanum2 = 0;
.Agora, suponha que seu construtor seja assim:
Isso vai lançar um
NullPointerException
comoobj
ainda não tenho uma referência declass A
.fonte
static A obj = new A();
abaixostatic int num2=0;
e você deve obter 1 e 1.A obj = new A(); int num1; int num2 = 0;
Se transformou em esta:A obj; int num1; int num2; obj = new A(); num2 = 0;
. Java faz isso, portanto,num1, num2
é definido no momento em que você chega aonew A()
construtor.O que o
static
modificador significa quando aplicado a uma declaração de variável é que a variável é uma variável de classe em vez de uma variável de instância. Em outras palavras ... há apenas umanum1
variável e apenas umanum2
variável.(À parte: uma variável estática é como uma variável global em algumas outras linguagens, exceto que seu nome não é visível em todos os lugares. Mesmo se for declarado como um
public static
, o nome não qualificado só é visível se for declarado na classe atual ou em uma superclasse , ou se for importado usando uma importação estática. Essa é a diferença. Um verdadeiro global é visível sem qualificação em qualquer lugar.)Então, quando você se refere
obj.num1
eobj.num2
, na verdade você está se referindo às variáveis estáticas cujas designações real sãoA.num1
eA.num2
. E da mesma forma, quando o construtor incrementanum1
enum2
, está incrementando as mesmas variáveis (respectivamente).O problema confuso em seu exemplo está na inicialização da classe. Uma classe é inicializada por padrão inicializando primeiro todas as variáveis estáticas e, em seguida, executando os inicializadores estáticos declarados (e blocos inicializadores estáticos) na ordem em que aparecem na classe. Nesse caso, você tem:
Acontece assim:
A estática começa com seus valores iniciais padrão;
A.obj
énull
eA.num1
/A.num2
são zero.A primeira declaração (
A.obj
) cria uma instância deA()
, e o construtor paraA
incrementosA.num1
eA.num2
. Quando a declaração é concluída,A.num1
eA.num2
são ambos1
, eA.obj
se refere àA
instância recém-construída .A segunda declaração (
A.num1
) não tem inicializador, entãoA.num1
não muda.A terceira declaração (
A.num2
) tem um inicializador que atribui zero aA.num2
.Assim, no final da inicialização da classe,
A.num1
é1
eA.num2
é0
... e é isso que suas instruções de impressão mostram.Esse comportamento confuso se deve ao fato de que você está criando uma instância antes da conclusão da inicialização estática e de que o construtor que está usando depende e modifica uma estática que ainda não foi inicializada. Isso é algo que você deve evitar fazer em código real.
fonte
1,0 está correto.
Quando a classe é carregada, todos os dados estáticos são inicializados antes de serem declarados. Por padrão, o int é 0.
static int num1;
que não faz nadastatic int num2=0;
isso escreve 0 a num2fonte
É devido à ordem dos inicializadores estáticos. As expressões estáticas nas classes são avaliadas de cima para baixo.
O primeiro a ser chamado é o construtor de
A
, que definenum1
enum2
ambos como 1:static A obj = new A();
Então,
é chamado e define num2 = 0 novamente.
É por isso que
num1
é 1 enum2
é 0.Como uma observação lateral, um construtor não deve modificar variáveis estáticas, isso é um design muito ruim. Em vez disso, tente uma abordagem diferente para implementar um Singleton em Java .
fonte
Uma seção no JLS pode ser encontrada: §12.4.2 .
Portanto, as três variáveis estáticas serão inicializadas uma a uma na ordem textual.
assim
Se eu mudar o pedido para:
O resultado será
1,1
.Observe que o
static int num1;
não é um inicializador de variável porque ( §8.3.2 ):E essa variável de classe é inicializada quando a classe é criada. Isso acontece primeiro ( §4.12.5 ).
fonte
Talvez ajude pensar dessa forma.
As classes são projetos para objetos.
Os objetos podem ter variáveis quando são instanciados.
As classes também podem ter variáveis. Eles são declarados como estáticos. Portanto, eles são definidos na classe em vez das instâncias do objeto.
Você só pode ter um de qualquer classe em um aplicativo, então é uma espécie de armazenamento global especificamente para essa classe. Essas variáveis estáticas podem, é claro, ser acessadas e modificadas de qualquer lugar em seu aplicativo (assumindo que sejam públicas).
Aqui está um exemplo de uma classe "Dog" que usa variável estática para rastrear o número de instâncias que criou.
A classe "Dog" é a nuvem, enquanto as caixas laranja são instâncias de "Dog".
consulte Mais informação
Espero que isto ajude!
Se você gosta de curiosidades, essa ideia foi introduzida pela primeira vez por Platão
fonte
A palavra-chave static é usada em java principalmente para gerenciamento de memória. Podemos aplicar palavras-chave estáticas com variáveis, métodos, blocos e classes aninhadas. A palavra-chave static pertence à classe do que à instância da classe. Para uma breve explicação sobre a palavra-chave estática:
http://www.javatpoint.com/static-keyword-in-java
fonte
Muitas das respostas acima estão corretas. Mas, realmente, para ilustrar o que está acontecendo, fiz algumas pequenas modificações abaixo.
Conforme mencionado várias vezes acima, o que está acontecendo é que uma instância da classe A está sendo criada antes que a classe A seja totalmente carregada. Portanto, o que é considerado o 'comportamento' normal não é observado. Isso não é muito diferente de chamar métodos de um construtor que pode ser substituído. Nesse caso, as variáveis de instância podem não estar em um estado intuitivo. Neste exemplo, as variáveis de classe não estão em um estado intuitivo.
A saída é
fonte
java não inicializa o valor de nenhum membro de dados estático ou não estático até que não seja chamado, mas o crie.
de modo que aqui quando num1 e num2 forem chamados em main então serão inicializados com os valores
num1 = 0 + 1; e
num2 = 0;
fonte