Статические поля по нулевой ссылке в Java

119

staticчлены ( staticполя или staticметоды) в Java связаны с их соответствующим классом, а не с объектами этого класса. Следующий код пытается получить доступ к статическому полю nullссылки.

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

Хотя main.getNull()возвращается null, работает и отображает value = 10. Как работает этот код?

крошечный
источник
16
Может быть, этот вопрос поможет вам понять это: почему вызов (статического) метода для нулевой ссылки не вызывает исключение NullPointerException?
Ян Герлингер
4
Ради интереса попробуйте Main main = null; main.getNull().value.
Марко Топольник
1
Это напоминает мне о том, что new Thread[]{}[-1].sleep(10);sleep () - статический метод. Раньше это было успешным в некоторых старых версиях Java.
hertzsprung 05

Ответы:

93

Такое поведение указано в Спецификации языка Java :

пустая ссылка может использоваться для доступа к переменной класса (статической), не вызывая исключения.

Более подробно, статическая оценка поля , например, Primary.staticFieldработает следующим образом (выделено мной) - в вашем случае Primary = main.getNull():

  • Основное выражение оценивается, а результат отбрасывается . [...]
  • Если поле не является пустым конечным полем, то результатом является значение указанной переменной класса в классе или интерфейсе, которое является типом первичного выражения. [...]
assylias
источник
5
Если у кого-то есть информация о том, почему был сделан этот выбор, было бы интересно.
6
@JonofAllTrades Я думаю, что это очевидно: разумно не генерировать никаких исключений при вызове нулевой ссылки, потому что это не имеет значения, поскольку метод статичен.
Malcolm
13
@JonofAllTrades: реальный вопрос заключается в том, почему был сделан выбор, разрешающий вызов статических членов в качестве экземпляра ... Мне кажется, что это только приводит к путанице и менее читаемому коду.
Falanwe
2
@Falanwe: Согласен, и это конструкция, в которой я не нуждался, хотя я в основном работаю в .NET, где это запрещено. Я предполагаю, что вы можете вызвать соответствующий статический метод подкласса, когда вам дается ссылка на родительский класс.
8
@Falanwe Это разрешено, но вызывает предупреждение в Eclipse: «Статическое поле Main.value должно быть доступно статическим способом». По крайней мере, те из нас, кто требователен к предупреждениям (например, я), избегали бы такого кода.
Artyom
19

Потому что, как вы сказали, статические поля не связаны с экземпляром.

Возможность доступа к статическим полям из ссылки на экземпляр (как вы это делаете) - это просто синтаксический сахар и не имеет дополнительного значения.
Ваш код компилируется в

main.getNull(); 
Main.value
SLaks
источник
7
Я бы назвал это синтаксическим сахаром, больше похоже на синтаксические опилки;)
Стивен Свенсен
3

Когда вы обращаетесь к статической переменной или методу с объектами во время компиляции, они преобразуются в имя класса. например:

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

Он напечатает значение статической переменной, потому что во время компиляции оно будет преобразовано в

System.out.println(Main.value);

Доказательство:

загрузите декомпилятор и декомпилируйте файл .class в файл .java, и вы увидите, что все статические методы или имя объекта, на которое ссылается переменная, автоматически заменяются именем класса.

Раис Алам
источник
3
  1. Доступ к staticчлену с именем класса разрешен, но не было написано, что нельзя получить доступ к staticчлену с помощью переменной ссылки на объект. Так что здесь работает.

  2. nullСсылка на объект переменной разрешен доступ к staticпеременной класса без бросать исключения либо во время компиляции или во время выполнения.

Кумар Вивек Митра
источник
2

Статическая переменная и метод всегда принадлежат классу. Поэтому, когда мы когда-либо создаем какой-либо объект, только нестатическая переменная и методы отправляются в кучу вместе с объектом, но статические находятся в области методов с классом. Вот почему, когда мы пытаемся получить доступ к статической переменной или методу, она преобразуется в точечную переменную имени класса или имя метода.

Пожалуйста, обратитесь к ссылке ниже для получения более подробной информации.

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


источник