来自null的java静态字段

use*_*818 7 java static nullpointerexception

我在互联网上找到了这个代码,并希望有人向我解释...

public class Foo {
    static int fubar = 42;

    public static void main(String[] args) {
        System.out.println(((Foo) null).fubar);
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码编译并正常工作,输出结果42.

怎么可能fubar从一个null没有抛出变量的情况下访问变量NullPointerException

dle*_*lev 10

它实际上并不是在寻找字段null,因为静态方法和字段不需要实例.强制类型表达式的类型Foo,并且fubar是一个已知的静态字段Foo,因此编译器和JVM没有问题.

通常情况下,您可以通过说出来访问该字段Foo.fubar.但是,Java足以提供一个快捷方式:如果您尝试在给定类型的实例表达式上访问静态字段或方法,它会将其视为您所说的[SomeType].theField.这就是这里发生的事情.


tem*_*def 4

由于该字段fubar已声明static,因此实际命名的任何地方都只有一个字段Foo.fubar。每个实例Foo共享这个副本。当您从对象中访问此字段时Foo,Java 不会尝试按照对象引用来查找它。相反,它在专门定义的位置查找对象,该位置可以独立于任何引用进行访问。因此,如果您尝试查找null对象的该字段,则可以这样做而不会导致任何类型的NullPointerException,因为该对象从未被引用。

编辑:字节码绝对是有序的!给定这个源文件:

public class Foo {
    static int fubar;
    public Foo() {
        ((Foo)null).fubar = 137;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是生成的字节码:

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
Run Code Online (Sandbox Code Playgroud)

请注意,第 12 行使用putstatic操作码,它将值存储到static字段中。它不引用任何类型的接收者对象。事实上,如果您注意到的话,生成的字节码(第 4-8 行)会对nullto进行强制转换Foo,但随后立即发出一个pop操作码将其从堆栈中弹出。它从未在字节码中的其他任何地方被引用。