来自null的java静态字段

时间:2011-07-21 20:23:23

标签: java static nullpointerexception

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

public class Foo {
    static int fubar = 42;

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

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

如何在不抛出fubar的情况下从null访问变量NullPointerException

3 个答案:

答案 0 :(得分:10)

实际上并没有在null上查找字段,因为静态方法和字段不需要实例。强制类型表达式Foo的类型,而fubarFoo上已知的静态字段,因此编译器和JVM没有问题。

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

答案 1 :(得分:4)

由于字段fubar已声明为static,因此实际上只有一个字段名为Foo.fubarFoo的每个实例共享此副本。当您从Foo对象访问此字段时,Java不会尝试按照对象引用来查找它。相反,它在特定定义的位置查找对象,可以独立于任何引用进行访问。因此,如果您尝试查找null对象的此字段,则可以在不引起任何NullPointerException的情况下执行此操作,因为永远不会引用该对象。

编辑:字节码肯定是有序的!鉴于此源文件:

public class Foo {
    static int fubar;
    public Foo() {
        ((Foo)null).fubar = 137;
    }
}

这是生成的字节码:

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

请注意,第12行使用putstatic操作码,该操作码将值存储到static字段中。它没有引用任何类型的接收器对象。实际上,如果您注意到,生成的字节码(第4-8行)会执行nullFoo的转换,但会立即发出pop操作码以将其弹出堆。它从未在字节码中的任何其他位置引用。

答案 2 :(得分:1)

fubar是一个静态成员,这个null的强制转换只是强调了在编译时而不是运行时分配静态变量。访问静态变量的更常见和等效的方法是Foo.fubar