在下面的代码中,我们在空引用上获得i
的值,但NPE
不存在。
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);
}
}
输出
null
10
答案 0 :(得分:7)
非正式地说,你可以想到这个
System.out.println(t.getTest().i);
等同于
System.out.println(Test.i);
因为i
是静态的。
这可能是最简单的答案。
严格地说,它们并不等同。其实
调用getTest()
但不使用其返回值
访问i
字段,如下面的测试所示。
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);
}
}
答案 1 :(得分:4)
我是一个静态变量,不需要实例来获取它的值。
答案 2 :(得分:4)
生成的字节码如下所示:
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]
如您所见,t.getTest()
确实被称为(21,22),但其结果未被使用(25)。以静态方式访问字段i
(26)。 Java字节码无法通过实例访问静态成员。请注意,这意味着t.getTest().i
和Test.i
不是等效表达式!在假设的语法中,等价物可能看起来像这样(使用我对这种语法直观的语义:
System.out.println( {t.getTest(); return Test.i;} );
请注意,字段test
也是如此:t.test.i
与Test.i
不同。虽然获得该字段不会产生任何副作用,并且本身不是一个有效的声明,但AspectJ仍然可以建议字段访问。
答案 3 :(得分:2)
Test t = new Test(); // initialize t
此处t
不是null
,因为它已初始化。因此,您没有获得NullPointerException
。
在下一个案例中,您希望自NullPointerException
返回t.getTest()
以后null
,
t.getTest().i;
i
是一个static
变量,您不需要实例来访问静态变量,您只需直接访问它们即可。因此,您也不会在此处获得NullPointerException
。
而且,
System.out.println(i); // is an another way to access static i
答案 4 :(得分:2)
来自Java Language Specifications
的 Receiver Variable Is Irrelevant For static Field Access
强> 的
以下程序演示了可以使用null引用来访问类(静态)变量而不会导致异常:
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);
}
}
它编译,执行和打印:
Mount Chocorua
即使favorite()的结果为null,也不会抛出NullPointerException。打印“Mount”表明主表达式确实在运行时完全评估,尽管事实上只使用其类型而不是其值来确定要访问的字段(因为字段山是静态的)。强> 的
即使主表达式(这是实例)在运行时被计算,也意味着,但是它的值被丢弃,只考虑它的类型。
答案 5 :(得分:1)
静态方法或变量不需要对对象的引用。您可以调用它甚至引用该对象为null。
答案 6 :(得分:1)
更具体地说,
在访问Static
变量时,编译器将生成与static
对应的getStatic
指令,并将用于访问static
。因此静态是与实例无关的,它们通过字段/方法仅使用run time constant pool的索引来解析,该索引稍后将用于求解字段引用位置。
有关详细信息,请参阅此答案:https://stackoverflow.com/a/21047440/1686291
答案 7 :(得分:0)
简单来说,编译器从类def中获取静态,而不是从对象中获取静态。
这就是为什么您可以将t.getTest().i
替换为Test.i
,它将是相同的。