可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This question already has an answer here:
-
Static fields on a null reference in Java
5 answers
-
How come invoking a (static) method on a null reference doesn't throw NullPointerException?
5 answers
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
回答1:
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.
回答2:
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);
}
}
回答3:
i being a static variable, no instance is needed to get its value.
回答4:
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.
回答5:
Test t = new Test(); // initialize t
Here t
isn't null
as it has been initialized. Thus, you do not get a NullPointerException
.
In next case where you expected a NullPointerException
since t.getTest()
returned null
,
t.getTest().i;
i
is a static
variable and you do not need to an instance to access static variables, you can just access them directly. Thus, you do not get NullPointerException
here too.
And moreover,
System.out.println(i); // is an another way to access static i
回答6:
Static methods or variables does not need a reference to the object. You can call it even reference to the object is null.
回答7:
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
回答8:
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.