微信公众号:Java 知其所以然
关注可了解更多的教程。问题或建议,请公众号留言;
实例方法的调用
代码
public class App {
public static void main(String[] args) {
App a = (App) null;
System.out.println(a);
a.test();
}
public void test(){
System.out.println("do something");
}
}
结果很明显,会报空指针异常。
分析字节码
主要来看这条语句
a.test()
它对应的字节码为
aload_1 // 加载局部变量表 1 号位的数据,也就是把引用 a 压栈
invokevirtual #5 // 执行实例方法,也就是执行 test() 方法
我们可以看出,当执行实例方法时,需要先将对象的引用压入操作数栈中,然后弹出栈去执行实例方法。
静态方法的调用
代码
public class App {
public static void main(String[] args) {
App a = (App) null;
System.out.println(a);
a.test();
}
public static void test(){
System.out.println("do something");
}
}
结果
do something
分析字节码
主要来看这条语句
a.test()
它对应的字节码为
aload_1 // 加载局部变量表 1 号位的数据,也就是把引用 a 压栈
pop // 弹出栈堆第一个元素,也就是弹出引用 a
invokestatic #5 // 调用执行静态方法 test()
我们可以看出,当执行静态方法时,先将对象的引用压入操作数栈中,然后又弹出栈去了,仅需要 invokestatic 这条指令执行静态方法就可以。
思考
引用 a 压入又弹出,说明执行 invokestatic 这条指令根本就不需要依赖引用 a 这个数据。从而说名了静态方法的调用依赖的是类对象( App.class )。