class B extends A
{
public void printValue()
{
super.printValue();// invokeStatic
System.out.println("Inside B");
}
}
public class Test
{
public static void main(String[] arr)
{
A a = new A();
B b = new B();
A.callMethod(a);// invokeVirtual
A.callMethod(b);// invokeVirtual
}
}
--〉通过Test.java保存--〉运行javac Test.java --〉javap -c -private Test
3条答案
按热度按时间svujldwt1#
从this site
如果仔细阅读Java VM规范,可以很容易地找到答案:
invokespecial和invokevirtual指令之间的区别在于invokevirtual基于对象的类调用方法。invokespecial指令用于调用示例初始化方法以及私有方法和当前类的超类的方法。
换句话说,invokespecial用于调用方法而不考虑动态绑定,以便调用特定类的方法版本。
在几种情况下,分派方法调用“而不考虑动态绑定”是很重要的:
首先,从一个构造函数链接到超类构造函数时。
第二,就像在
super.foo()
中一样,当从一个方法调用一个超类的实现时,如果这个类或它的任何子类覆盖了那个方法,那么 invokevirtual 就会转到错误的地方。第三,当一个类想要选择使用哪个
default
版本的方法时,如上面的
class C
有一个菱形继承问题,所以它需要选择调用哪个默认方法。invokespecial 允许它分派到K
的版本,但是如果K.super.f
通过 invokevirtual 分派,调用将返回到C.f
。1l5u6lss2#
http://www.artima.com/underthehood/invocationP.html上面的链接给出了有价值的例子,清楚地解决了我的问题。
调用main时()在上面定义的Subclass中,它必须打印“Superclass的interesting method”。如果使用invokevirtual,它将打印“Subclass的interesting method”。为什么?因为虚拟机将选择interestingMethod()根据对象的实际类来调用,也就是Subclass,所以它将使用Subclass的interestingMethod另一方面,使用invokespecial,虚拟机将根据引用的类型选择方法,因此将调用Superclass版本的interestingMethod()。
w80xi6nr3#
谢谢你阅读到这个解释:如果它能帮助你在方法调用期间识别汇编指令的创建,请不要忘记投赞成票。
首先我要告诉大家的是,invokeStatic,invokeSpecial,invokeVirtual,invokeInterface等都是编译器编译后生成的汇编指令,大家都知道编译后得到的是.class文件格式,我们无法读取,但是java提供了一个工具,名为**“javap”**。
我们可以使用javap命令读取我们的.class文件汇编指令。默认情况下,我们看不到私有方法汇编指令,所以我们需要使用-private。下面是查看java编译器生成的汇编指令的命令:
1.想象你有A.java类
public void printValue(){ System.out.println(“A内部”);}
public static void callMethod(A a){ a.printValue();{\fnSimHei\bord1\shad1\pos(200,288)}
1.打开cmd提示符并转到包含Java文件A.java的文件夹。
1.运行javac A.java。
1.现在生成了一个. class文件,其中包含汇编指令,但您无法读取它。
1.现在运行javap -c A
1.您可以看到方法调用的程序集生成--〉a.printValue();
1.如果printValue()方法是private,则需要使用javap -c -private A。
1.你可以将printValue()设置为private / static / public / private static。
1.还有一件事要记住,首先编译器检查方法被调用的对象,然后找到它的类类型,并在该类中找到该方法是否可用。
**注意:**现在请记住,如果我们的调用方法是静态的,则生成invokeStatic汇编,如果它的私有的,则生成invokeSpecial汇编指令,如果它的公共的,则生成invokeVirtual指令。公共方法并不意味着每次都生成invokeVirtual指令。在super.printValue()的情况下,从A的子类调用是例外情况。即,如果A是B的父类,B包含相同的方法printValue(),则它将生成invokeVirtual(dynamic),但如果B中的printValue()具有super.printValue()作为其第一个语句,则即使A的printValue()是公共的,也会生成invokeStatic。
让我们也试试这个:
--〉通过Test.java保存--〉运行javac Test.java --〉javap -c -private Test