Campos estáticos en una referencia nula en Java

119

staticlos miembros ( staticcampos o staticmétodos) en Java están asociados con su clase respectiva en lugar de los objetos de esta clase. El siguiente código intenta acceder a un campo estático en una nullreferencia.

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);
    }
}

Aunque main.getNull()vuelve null, funciona y se muestra value = 10. ¿Cómo funciona este código?

Minúsculo
fuente
4
Para divertirse, intente Main main = null; main.getNull().value.
Marko Topolnik
1
Esto me recuerda new Thread[]{}[-1].sleep(10);dónde sleep () es un método estático. Esto solía tener éxito en algunas versiones anteriores de Java.
hertzsprung

Respuestas:

93

Ese comportamiento se especifica en la Especificación del lenguaje Java :

se puede usar una referencia nula para acceder a una variable de clase (estática) sin causar una excepción.

En más detalles, una evaluación de campo estática , como Primary.staticFieldfunciona de la siguiente manera (énfasis mío), en su caso Primary = main.getNull(),:

  • Se evalúa la expresión primaria y se descarta el resultado . [...]
  • Si el campo es un campo final que no está en blanco, entonces el resultado es el valor de la variable de clase especificada en la clase o interfaz que es el tipo de la expresión primaria. [...]
Assylias
fuente
5
Si alguien tiene información sobre por qué se hizo esta elección, sería interesante.
6
@JonofAllTrades Creo que esto es obvio: es razonable no lanzar ninguna excepción al llamar a una referencia nula porque no importa ya que el método es estático.
Malcolm
13
@JonofAllTrades: la verdadera pregunta es por qué se tomó la decisión de permitir que los miembros estáticos sean llamados como instancia ... Para mí, parece que solo genera confusión y un código menos legible.
Falanwe
2
@Falanwe: De acuerdo, y es una construcción para la que no he tenido una necesidad, aunque trabajo principalmente en .NET donde no está permitido. Supongo que es posible que desee llamar al método estático apropiado de una subclase cuando se le da una referencia a una clase principal.
8
@Falanwe Esto está permitido, pero genera una advertencia en Eclipse: "Se debe acceder al campo estático Main.value de forma estática". Al menos aquellos de nosotros exigentes con las advertencias (como yo) evitaríamos ese código.
Artyom
19

Porque, como dijiste, los campos estáticos no están asociados con una instancia.

La capacidad de acceder a campos estáticos desde una referencia de instancia (como lo está haciendo) es simplemente un azúcar sintáctico y no tiene ningún significado adicional.
Tu código se compila a

main.getNull(); 
Main.value
SLaks
fuente
7
Yo lo llamaría azúcar sintáctico, más como serrín sintáctico;)
Stephen Swensen
3

Siempre que accede a una variable o método estático con objetos en el momento de la compilación, se convierte al nombre de clase. p.ej:

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

Imprimirá el valor del valor de la variable estática porque en el momento de la compilación se convertirá a

System.out.println(Main.value);

Prueba:

descargue el decompilador y descompile su archivo .class en un archivo .java y podrá ver que todos los métodos estáticos o el nombre del objeto referido a la variable se reemplaza automáticamente por el nombre de la clase.

Rais Alam
fuente
3
  1. Acceder a un staticmiembro con el nombre de la clase es legal, pero no se escribió que no se puede acceder al staticmiembro utilizando la variable de referencia del objeto. Entonces funciona aquí.

  2. A una nullvariable de referencia de objeto se le permite acceder a una staticvariable de clase sin lanzar una excepción en tiempo de compilación o ejecución.

Kumar Vivek Mitra
fuente
2

La variable estática y el método siempre pertenecen a la clase. Entonces, cuando creamos cualquier objeto, solo la variable no estática y los métodos se acumulan junto con el objeto, pero la estática reside en el área de método con la clase. Es por eso que cada vez que intentamos acceder a una variable o método estático, se convierte en el nombre de la clase, la variable de punto o el nombre del método.

Consulte el enlace a continuación para obtener más detalles.

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


fuente