有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java当invokeVirtual存在时为什么需要invokeSpecial

有三个操作码可以调用Java方法。显然,invokeStatic只是用于静态方法调用

据我所知,调用构造函数和私有方法时使用invokespecial。那么,我们需要在运行时区分私有和公共方法调用吗?它可以用相同的操作码调用,比如invokevirtual

JVM是否处理私有和公共方法定义?据我所知,在开发阶段封装只需要公共和私有关键字


共 (3) 个答案

  1. # 1 楼答案

    感谢您阅读该解释:如果它有助于您在方法调用期间识别汇编指令的创建,请不要忘记向上投票 这里我将解释静态绑定和动态绑定

    首先,我要告诉大家,invokeStatic、invokeSpecial、invokeVirtual、invokeInterface等是编译器在编译过程后生成的汇编指令。 我们都知道我们有一个。编译后的类文件格式,我们无法读取它。但是java提供了一个名为“javap”的工具

    我们可以读出我们的名字。使用javap命令对文件汇编指令进行分类。默认情况下,我们看不到私有方法汇编指令,所以我们需要使用-private。以下是查看java编译器生成的汇编指令的命令:

    1. 假设你有一个.java类

      甲级 { public void printValue() { 系统出来println(“A内部”); }

      公共静态无效调用方法(A) { a、 printValue(); } }

    2. 打开cmd prompt并转到包含java文件A.java的文件夹

    3. 运行javac A.java

    4. 现在生成了一个.class文件,其中包含汇编指令,但您无法读取它

    5. 现在运行javap-ca

    6. 您可以看到方法调用的程序集生成>a.printValue()

    7. 如果printValue()方法是私有的,则需要使用javap-c-private A

    8. 您可以将printValue()设置为private/static/public/private static

    9. 还有一件事需要记住,第一个编译器检查调用方法的对象。然后找到它的类类型,并在该类中找到该方法(如果可用或不可用)

    注意:现在请记住,如果调用方法是静态的,则会生成invokeStatic汇编;如果调用方法是私有的,则会生成invokeSpecial汇编指令;如果调用方法是公共的,则会生成invokeVirtual指令。公共方法并不意味着每次生成invokeVirtual指令时。以防超级。来自A的子类的printValue()调用是例外情况。i、 e.如果A是B的父类,B包含相同的方法printValue(),那么它将生成invokeVirtual(动态),但如果B中的printValue()具有super。printValue()作为其第一条语句,然后生成invokeStatic,即使A的printValue()是公共的

    我们也来试试这个:

    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
    }
    }
    

    >;通过测试保存它。JAVA >;运行javac测试。JAVA >;javap-c-私有测试

  2. # 2 楼答案

    this site

    The answer can be easily found if one reads the Java VM Spec carefully:

    The difference between the invokespecial and the invokevirtual instructions is that invokevirtual invokes a method based on the class of the object. The invokespecial instruction is used to invoke instance initialization methods as well as private methods and methods of a superclass of the current class.

    换句话说,invokespecial用于调用方法,而不考虑动态绑定,以便调用特定类的方法版本

  3. # 3 楼答案

    http://www.artima.com/underthehood/invocationP.html 上面的链接提供了一些有价值的例子,可以清楚地回答我的问题

    class Superclass {
    
        private void interestingMethod() {
            System.out.println("Superclass's interesting method.");
        }
    
        void exampleMethod() {
            interestingMethod();
        }
    }
    
    class Subclass extends Superclass {
    
        void interestingMethod() {
            System.out.println("Subclass's interesting method.");
        }
    
        public static void main(String args[]) {
            Subclass me = new Subclass();
            me.exampleMethod();
        }
    }
    

    当您在上面定义的子类中调用main()时,它必须打印“超类的有趣方法”如果使用invokevirtual,它将打印“子类有趣的方法”为什么?因为虚拟机会根据对象的实际类(即子类)选择要调用的interestingMethod()。所以它将使用子类的interestingMethod()。另一方面,使用invokespecial,虚拟机将根据引用的类型选择方法,因此将调用超类版本的interestingMethod()