Campos estáticos em uma referência nula em Java

119

staticmembros ( staticcampos ou staticmétodos) em Java são associados a suas respectivas classes, e não aos objetos dessa classe. O código a seguir tenta acessar um campo estático em uma nullreferência.

public class Main
{
    private static final int value = 10;

    public Main getNull()
    {
        return null;
    }

    public static void main(String[] args)
    {
        Main main=new Main();
        System.out.println("value = "+main.getNull().value);
    }
}

Embora main.getNull()retorne null, ele funciona e exibe value = 10. Como funciona esse código?

Muito pequeno
fonte
16
Talvez esta pergunta possa ajudá-lo a entendê-lo: por que invocar um método (estático) em uma referência nula não lança NullPointerException?
Jan Gerlinger
4
Para se divertir, experimente Main main = null; main.getNull().value.
Marko Topolnik de
1
Isso me lembra de new Thread[]{}[-1].sleep(10);onde sleep () é um método estático. Isso costumava ser bem-sucedido em algumas versões anteriores do Java.
hertzsprung

Respostas:

93

Esse comportamento é especificado na Especificação da linguagem Java :

uma referência nula pode ser usada para acessar uma variável de classe (estática) sem causar uma exceção.

Em mais detalhes, uma avaliação de campo estática , como Primary.staticFieldfunciona da seguinte maneira (grifo meu) - no seu caso Primary = main.getNull():

  • A expressão primária é avaliada e o resultado é descartado . [...]
  • Se o campo for um campo final não vazio, o resultado será o valor da variável de classe especificada na classe ou interface que é o tipo da expressão primária. [...]
assilias
fonte
5
Se alguém tiver informações sobre por que essa escolha foi feita, isso seria interessante.
6
@JonofAllTrades Acho que isso é óbvio: é razoável não lançar nenhuma exceção ao chamar uma referência nula porque isso não importa, já que o método é estático.
Malcolm de
13
@JonofAllTrades: a verdadeira questão é por que a escolha de permitir que membros estáticos sejam chamados como instância foi feita ... Para mim, parece que só leva a confusão e código menos legível.
Falanwe
2
@Falanwe: Concordo, e é uma construção da qual não tive necessidade, embora trabalhe principalmente em .NET onde não é permitido. Eu acho que você pode querer chamar o método estático apropriado de uma subclasse quando você receber uma referência a uma classe pai.
8
@Falanwe Isso é permitido, mas levanta um aviso no Eclipse: "O campo estático Main.value deve ser acessado de forma estática". Pelo menos aqueles de nós exigentes quanto aos avisos (como eu) evitariam esse código.
Artyom
19

Porque, como você disse, os campos estáticos não estão associados a uma instância.

A capacidade de acessar campos estáticos de uma referência de instância (como você está fazendo) é meramente um açúcar sintático e não tem nenhum significado adicional.
Seu código compila para

main.getNull(); 
Main.value
SLaks
fonte
7
Eu o chamaria de açúcar sintático, mais como serragem sintática;)
Stephen Swensen
3

Sempre que você acessa uma variável ou método estático com objetos em tempo de compilação, ele é convertido para o nome da classe. por exemplo:

Main main = null;
System.out.println(main.value);

Irá imprimir o valor do valor da variável estática porque em tempo de compilação será convertido para

System.out.println(Main.value);

Prova:

baixe o descompilador e descompile seu arquivo .class para o arquivo .java e você poderá ver todos os métodos estáticos ou o nome do objeto referenciado à variável é automaticamente substituído pelo nome da classe.

Rais Alam
fonte
3
  1. Acessar um staticmembro com o nome da classe é legal, mas não foi escrito que não se pode acessar o staticmembro usando a variável de referência do objeto. Então funciona aqui.

  2. Uma nullvariável de referência de objeto tem permissão para acessar uma staticvariável de classe sem lançar uma exceção em tempo de compilação ou execução.

Kumar Vivek Mitra
fonte
2

A variável estática e o método sempre pertencem à classe. Portanto, sempre que criamos qualquer objeto, apenas variáveis ​​e métodos não estáticos vão para o heap junto com o objeto, mas estático reside na área de método com a classe. É por isso que, sempre que tentamos acessar uma variável estática ou método, ele é convertido em variável de ponto de nome de classe ou nome de método.

Por favor, consulte o link abaixo para mais detalhes.

http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html


fonte