Почему этот метод вызывается для нулевого объекта без NullPointerException?

В чем причина выхода? Я знаю, что он печатает Hello World, но не знаю почему, поскольку он должен давать NullPointerException.

public class Null
{
    public static void greet()
    {
        System.out.println("Hello World");

    }
    public static void main(String[] args)
    {
        ((Null)null).greet();
    }
}

Ответы

Ответ 1

Это потому, что greet() является статическим методом. Итак,

((Null)null).greet();

эквивалентно

Null.greet()

Ответ 2

Поскольку greet является статическим методом, экземпляр класса не требуется (и не используется...) для его вызова.

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

Ответ 3

Когда мы пытаемся использовать ссылку на объект с нулевым значением, выдается NullPointerException. Итак, в вашем примере вы можете подумать, что метод greet() успешно вызывается из нулевого объекта.

Но внимательно посмотрите на сигнатуру метода, перед ней стоит модификатор static. Если вы вызываете статический метод для объекта с нулевой ссылкой, вы не получите исключение, и код будет выполняться без каких-либо исключений. Это потому, что статические методы являются методами класса, а не методом экземпляра.

Поэтому, когда вы компилируете свой код, ((Null)null).greet() просто преобразуется в Null.greet().

Для простоты рассмотрите код ниже:

Null obj1 = null;
Null obj2 = new Null();
obj1.greet();
obj2.greet();

Поскольку greet() является здесь статическим методом, во время этого вызова компилятор метода просто игнорирует, есть ли внутри объекта что-либо созданное или нет. Он будет просто скомпилирован как Null.greet() для obj1 и obj2.

Однако попробуйте удалить модификатор static из метода. Вы обнаружите, что NullPointerException вы ожидали.

Ответ 4

Это допустимое поведение, поскольку:

((Null)null).greet();

будет похоже на вызов статического метода greet в классе Null.

Это даже показано как правильное поведение в примере 15.11.1-2. Receiver Variable Is Irrelevant For static Field Access JLS:

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

class Test3 {
    static String mountain = "Chocorua";
    static Test3 favorite(){
        System.out.print("Mount ");
        return null;
    }
    public static void main(String[] args) {
        System.out.println(favorite().mountain);
    }
}

И объяснение того, что происходит, почему оно компилируется и печатается Mount Chocorua:

Даже если результатом favorite() является null, NullPointerException не выбрасывается. То, что "Mount" напечатано, демонстрирует, что первичное выражение действительно полностью вычисляется во время выполнения, несмотря на тот факт, что только его тип, а не его значение, используется для определения того, к какому полю обращаться (поскольку поле mountain является статическим).

Так что в вашем случае это только тип выражения ((Null)null), который оценивается как Null, который используется для определения, какой метод вызывать (в классе Null есть статический метод greet, поэтому он не является проблема).