Qual é a diferença na memória entre uma variável atribuída a null e uma não atribuída

8

Qual é a diferença na memória entre uma variável atribuída a null e uma não atribuída?

Eu sei que há uma diferença no uso, mas qual é a diferença na memória?

abu_abdelbarr
fonte
1
Compartilhar sua pesquisa ajuda a todos . Conte-nos o que você tentou e por que ele não atendeu às suas necessidades. Isso demonstra que você dedicou um tempo para tentar ajudar a si mesmo, evita reiterar respostas óbvias e, acima de tudo, ajuda a obter uma resposta mais específica e relevante. Veja também How to Ask
gnat

Respostas:

11

Não há diferença entre os dois "na memória".

Na especificação da linguagem Java, 4.12.5. Valores Iniciais das Variáveis :

Toda variável em um programa deve ter um valor antes que seu valor seja usado:

  • Cada variável de classe, variável de instância ou componente de matriz é inicializado com um valor padrão quando é criado (§15.9, §15.10.2):

...

    • Para todos os tipos de referência (§4.3), o valor padrão é nulo.

...

    • Uma variável local (§14.4, §14.14) deve receber explicitamente um valor antes de ser usada, tanto pela inicialização (§14.4) quanto pela atribuição (§15.26), de maneira que possa ser verificada usando as regras para atribuição definida (§ 16 (Cessão Definida)).

As variáveis ​​de referência no nível da classe ou do objeto receberão um valor nulo.

As variáveis ​​de referência no nível do método (pilha) terão um valor não especificado (usando o termo C ++). Na prática, isso geralmente é nulo, mas o padrão não especifica o que está na variável de referência, apenas que ele deve ser atribuído antes do uso. O uso de uma variável de referência na pilha de qualquer outra maneira que não a atribuição como seu primeiro uso resultará em um erro de compilação.


fonte
Quando você declara uma variável sem inicializá-la como nula e, em seguida, inicializa-a em um if-thenbloco, o compilador informa que a variável talvez não seja inicializada à frente no código se o thenbloco não for executado. Se você inicializá-lo para nullo código compila. Por que isso, considerando que "uma referência não atribuída explicitamente a um valor terá o valor nulo" ?
Tulains Córdova
@Snowman Isso não é um detalhe de implementação? Somente variáveis ​​de classe, variáveis ​​de instância e componentes de matriz precisam ser inicializados com seus valores padrão. Não há requisitos para variáveis ​​locais e você não pode usá-las antes de serem inicializadas. Se você visse uma variável local não inicializada na memória, veria o que a implementação acontecer com ela, o que pode não envolver a inicialização, nullpois seria um trabalho desnecessário fazê-lo.
Doval
@ Snowman - Como é ilegal usar um local anterior antes de atribuir um valor, se uma variável local não inicializada recebe um valor inicial é um detalhe de implementação.
David Hammen
1
Por favor, veja minha edição mais recente. Eu culpo o café insuficiente numa segunda-feira de manhã.
4

Qual é a diferença entre uma variável atribuída a null e outras não atribuídas na memória?

Não existe uma variável não atribuída em Java. Membros de dados da classe que não têm uma atribuição explícita recebem o valor padrão para o tipo, nulo para um objeto ou algo semelhante a 0 para tipos primitivos.

Variáveis ​​locais ficam na pilha. (Locais não primitivos, como MyType footambém vivem na pilha, como referências.) A alocação da pilha é simples. Se um bloco contiver declarações para variáveis ​​locais, o espaço necessário para essas variáveis ​​locais será reservado na pilha. Se valores são atribuídos a essas variáveis ​​locais no ajuste da pilha para acomodar essas variáveis ​​locais é irrelevante.

A razão pela qual isso não importa é se as variáveis ​​locais têm ou não um valor atribuído no momento em que a execução entra no bloco. Uma razão é que o tamanho necessário não muda. As primitivas têm um tamanho fixo e as não primitivas são na verdade referências. (O objeto referenciado reside na pilha e não na pilha.) O segundo motivo é que o uso de uma variável local que não foi atribuída a um valor é um erro de compilação. Isso deixa ao tempo de execução Java a atribuição de algum valor (não necessariamente o padrão) a uma variável local declarada, mas não atribuída.

David Hammen
fonte
Em algum lugar na sua resposta está a explicação para isso: Quando você declara uma variável sem inicializá-la como nula, e a inicializa dentro de um if-thenbloco, o compilador informa que a variável talvez não seja inicializada à frente no código se o thenbloco não for executado. Se você inicializá-lo para nullo código compila. Por que isso, considerando que "uma referência não atribuída explicitamente a um valor terá o valor nulo" ? Mas ainda não está claro o suficiente para mim. Você poderia explicar em outras palavras?
Tulains Córdova
2
As variáveis ​​locais não precisam receber um valor inicial. Eles precisam receber um valor antes do uso inicial. Se a memória associada a essa variável recebe um valor inicial explícito, mesmo no caso de uma declaração sem atribuição, é um detalhe da implementação. A memória existe (é assim que as pilhas funcionam), mas esse espaço pode ser preenchido com o que quer que esteja na memória antes de ajustar a pilha.
David Hammen
@ user61852 - O fato de uma referência não atribuída explicitamente a um valor ter o valor null é verdadeiro para os membros da classe, mas não necessariamente para as variáveis ​​locais. Se você estiver compilando seu código com a depuração ativada, o compilador quase certamente inicializará suas variáveis ​​locais não primitivas não inicializadas null. Isso simplifica bastante o desenvolvimento do depurador Java. Mas e se você compilar com a depuração desativada? Agora essa inicialização é um trabalho extra desnecessário. O conteúdo dessa memória é irrelevante porque é sabido que a memória conterá um valor válido no primeiro uso.
David Hammen
De uma perspectiva de bytecode, variáveis ​​locais são alocadas na pilha. O JITter, no entanto, pode decidir decidir que uma entrada de pilha específica não deve realmente ser armazenada na pilha, mas os armazenamentos e cargas dessa entrada devem ser direcionados para um registro de CPU específico. Além disso, se o JITter determinar que, uma vez que a execução atinja um determinado ponto, não há como uma entrada de pilha ser lida sem ter sido reescrita, isso pode reatribuir o registro associado dessa entrada para outra finalidade.
supercat
1

Primeiro, não há realmente necessidade de se preocupar com o espaço usado pelas variáveis ​​locais. Em uma linha, eu posso alocar uma matriz de 100.000 números inteiros, que ocuparão mais espaço do que todas as variáveis ​​locais que você jamais usará.

Segundo, seu código é compilado por um compilador que provavelmente será inteligente. Se sua variável não for inicializada, ela não será usada (porque o compilador não permite o uso de variáveis ​​não inicializadas). Mas se você inicializá-lo para zero, ele ainda não será usado! O compilador descobrirá facilmente que ele não é usado e na verdade não usa espaço para a variável. Mesmo se for usado, o compilador descobrirá facilmente que o valor é nulo e usará nil em vez da variável.

Mas terceiro, são todas as micro-otimizações que não ajudarão você a otimizar um programa de forma alguma. Você está tentando salvar quatro ou oito bytes. Concentre-se em economizar megabytes, se quiser salvar alguma coisa.

E, por último, enquanto algumas pessoas afirmam que as variáveis ​​sempre devem ser inicializadas, isso não é verdade em Java. Você só deve definir uma variável para um valor significativo. Digamos que você queira definir uma variável para o nome de uma pessoa, e esqueça de fazer isso em um caminho de código. Se você inicializar cegamente a variável para zero, o compilador não poderá informar. Sem a inicialização, o compilador pode e irá informar sobre seu erro.

gnasher729
fonte