我试图找出一个提供不可用参数的方法调用如何在调用代码行之前抛出异常 - 在它到达方法行之前。 以下是一个例子
1. static Integer x;
2. public static void main(String args[]){
3. doStuff(x)} //null pointer exception thrown on this line
//lines 4-49
50. public static void doStuff(int z){}
这里我发送一个Integer对象引用该方法,并且由于自动装箱,Integer对象是一个有效的发送引用。 如果在到达第50行之前未将调用的方法加载到堆栈中,为什么JVM在第3行抛出空指针异常时尚未获得方法签名呢?
答案 0 :(得分:6)
因为null
不是原语int
的有效值。
由于自动装箱,Integer
对象是接受原语int
的方法的有效参数,所以你是对的。但是,如果您在此处描述,则Integer
永远不会被初始化,因此null
(Integer
对象的默认未初始化值与int
不同,这是0)。
这意味着JVM尝试通过调用null
将int
强制转换为原始null.intValue()
,以便它适合所调用的方法 - 这就是NPE所在的位置被抛出。
仅仅是FYI,在调用它的行下面声明该方法的事实没有区别,因为Java没有被解释,它被编译成字节码。
答案 1 :(得分:2)
null
不能autounboxed
为有效int
可能有助于查看生成的实际字节码。
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field i:Ljava/lang/Integer;
3: invokevirtual #3; //Method java/lang/Integer.intValue:()I <--- Your error comes from this line
6: invokestatic #4; //Method doStuff:(I)V
9: return
答案 2 :(得分:1)
因为您的方法参数类型是“int”而不是“Integer”。所以JVM想要将Integer对象转换为“int”基元类型,并且对象为null。所以这个转换抛出异常。
答案 3 :(得分:1)
If the invoked method is not loaded onto the stack until the line 50 is reached
- 这是一个不正确的假设。
在autobox并将Integer视为int或反之亦然时,编译器会插入对intValue()或Integer.valueof()的调用。
如果你在类文件中使用反编译器,那就更明显了:
Integer x = null;
...
doStuff(x.intValue());
因此在Null上调用intValue()
- 这会导致空指针异常。
答案 4 :(得分:0)
假设我们有以下代码:
class Test {
public static Integer i;
public static void test(int x) {}
public static void main(String[] argv) {
test(i);
}
}
当我们反编译程序时,我们看到main
编译如下:
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field i:Ljava/lang/Integer;
3: invokevirtual #3; //Method java/lang/Integer.intValue:()I
6: invokestatic #4; //Method test:(I)V
9: return
因此,即使在调用该方法之前,JVM也会调用i.intValue()
,这显然会产生NullPointerException
。