I found this code on the Internet, and would love for someone to explain it to me...
public class Foo {
static int fubar = 42;
public static void main(String[] args) {
System.out.println(((Foo) null).fubar);
}
}
This code compiles and works correctly, outputting the result 42
.
How is it possible that the variable fubar
is accessed from a null
without throwing a NullPointerException
?
It's not actually looking for the field on null
, because static methods and fields don't require an instance. The cast makes the type of the expression Foo
, and fubar
is a known static field on Foo
, so the compiler and JVM have no issue.
Normally, you'd access the field by saying Foo.fubar
. However, Java is nice enough to provide a shortcut: if you try to access a static field or method on an instance expression of a given type, it will treat it as if you had said [SomeType].theField
. That's what's occurring here.
Because the field fubar
is declared static
, there is only one field anywhere actually named Foo.fubar
. Each instance of Foo
shares this one copy. When you access this field out of a Foo
object, Java doesn't try following the object reference to find it. Instead, it looks up the object in a specially-defined location that can be accessed independently of any reference. Consequently, if you try looking up this field of the null
object, you can do so without causing any sort of NullPointerException
, since the object is never referenced.
EDIT: Bytecode is definitely in order! Given this source file:
public class Foo {
static int fubar;
public Foo() {
((Foo)null).fubar = 137;
}
}
Here's the generated bytecode:
0: aload_0
1: invokespecial #1; //Method Object."<init>":()V
4: aconst_null
5: checkcast #2; //class Foo
8: pop
9: sipush 137
12: putstatic #3; //Field fubar:I
15: return
Notice that line 12 uses the putstatic
opcode, which stores a value into a static
field. It doesn't reference a receiver object of any sort. In fact, if you'll notice, the generated bytecode (lines 4-8) does a cast of null
to Foo
, but then immediately issues a pop
opcode to pop it off the stack. It's never referenced anywhere else in the bytecode.
fubar is a static member this cast of null just highlights the allocation of static variables at compile time rather than runtime. A much more common and equivalent way of accessing the static variable is this Foo.fubar
精彩评论