Why not a NullPointerException while accessing sta

2019-01-26 11:59发布

Here in following code we are getting value of i on a null reference, though a NPE is not there.

public class Test {
    static int i = 10;

    Test getTest() {
        return null;    
    }

    public static void main(String args[]) {
        Test t = new Test();
        System.out.println(t.getTest());  
        System.out.println(t.getTest().i);
    }
}

output

null
10

8条回答
手持菜刀,她持情操
2楼-- · 2019-01-26 12:20

The generated bytecode looks like this:

18  getstatic java.lang.System.out : java.io.PrintStream [24]
21  aload_1 [t]
22  invokevirtual experiments.Experiments.getTest() : experiments.Experiments [30]
25  pop
26  getstatic experiments.Experiments.i : int [10]
29  invokevirtual java.io.PrintStream.println(int) : void [38]

As you see, t.getTest() is indeed called (21,22), but its result not used (25). The field i is accessed in a static way (26). Java Bytecode has no way of accessing static members via an instance. Note that this means that t.getTest().i and Test.i are not equivalent expressions! In a hypothetical syntax, the equivalent could look like this (using the semantics I'd find intuitive for this syntax:

System.out.println( {t.getTest(); return Test.i;} );

Note that the same holds for a field test: t.test.i is different from Test.i. Although getting the field can't have any side effects and is not a valid statement on its own, the field access could still be advised by AspectJ or something similar.

查看更多
Bombasti
3楼-- · 2019-01-26 12:22

Static methods or variables does not need a reference to the object. You can call it even reference to the object is null.

查看更多
聊天终结者
4楼-- · 2019-01-26 12:22

To be more specific,

While accessing the Static variable, compiler will generate an getStatic instruction corresponding to that static and it will be used to access that static. thus static are instance independent they are resolved by the field/method using just an index to the run time constant pool that will be later used to solve the field reference location..

For more details refer this SO answer : https://stackoverflow.com/a/21047440/1686291

查看更多
霸刀☆藐视天下
5楼-- · 2019-01-26 12:28

Simply speaking, compiler takes statics from class def, not from an object. That is why you can replace t.getTest().i with Test.i and it will be the same.

查看更多
地球回转人心会变
6楼-- · 2019-01-26 12:30

From Java Language Specifications

Receiver Variable Is Irrelevant For static Field Access

The following program demonstrates that a null reference may be used to access a class (static) variable without causing an exception:

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

It compiles, executes, and prints:

Mount Chocorua

Even though the result of favorite() is null, a NullPointerException is not thrown. That "Mount " is printed demonstrates that the Primary expression is indeed fully evaluated at run time, despite the fact that only its type, not its value, is used to determine which field to access (because the field mountain is static).

Implies even though primary expression (Here is instance) is evaluated at run time, but its value is discarded and only its type is considered.

查看更多
仙女界的扛把子
7楼-- · 2019-01-26 12:33

Informally speaking, you can think of this

System.out.println(t.getTest().i);

as being equivalent to

System.out.println(Test.i);

because i is static.

This is the simplest answer probably.

Strictly speaking, they are not equivalent. Actually
getTest() is called but its return value is not used
for accessing the i field as this test below shows.

public class Test {
    static int i = 10;

    Test getTest() {
        System.out.println("Method getTest() called!");
        return null;    
    }

    public static void main(String args[]) {
        Test t = new Test();
        System.out.println(t.getTest());  
        System.out.println(t.getTest().i);
    }
}
查看更多
登录 后发表回答