首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当invokeVirtual存在时为什么需要invokeSpecial

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

Stack Overflow用户
提问于 2012-12-07 21:39:30
回答 3查看 15.6K关注 0票数 58

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

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

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-12-07 22:12:45

http://www.artima.com/underthehood/invocationP.html上面的链接清楚地给出了有价值的例子,解决了我的问题。

代码语言:javascript
复制
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,它将输出"Subclass's interesting method“。为什么?因为虚拟机将根据对象的实际类(即子类)选择要调用的interestingMethod()。因此它将使用子类的interestingMethod()。另一方面,使用invokespecial,虚拟机将根据引用的类型选择方法,因此将调用超类版本的interestingMethod()。

票数 32
EN

Stack Overflow用户

发布于 2012-12-07 21:46:48

来自this site

如果仔细阅读

VM规范,答案很容易找到:

invokespecial和invokevirtual指令之间的区别在于,invokevirtual基于对象的类调用方法。调用专用指令用于调用实例初始化方法以及私有方法和当前类的超类的方法。换句话说,invokespecial用于调用方法,而不考虑动态绑定,以便调用方法的特定类版本。

票数 47
EN

Stack Overflow用户

发布于 2018-10-09 13:34:53

感谢你读出这个解释:如果它能帮助你在方法调用过程中识别汇编指令的创建,请不要忘记向上投票,我在这里解释静态绑定与动态绑定。

首先我要告诉你,invokeStatic,invokeSpecial,invokeVirtual,invokeInterface等都是编译器编译后生成的汇编指令。众所周知,编译后得到的是.class格式的文件,无法读出。但是java为命名的"javap"提供了一个工具。

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

  1. 映像您有A.java类

A类{ public void printValue() { System.out.println("Inside A");}

public static void callMethod(A a) { a.printValue();}}

  • 打开cmd提示符并转到包含java文件A.java的文件夹。

  • 运行javac A.java。

  • Now生成A.class文件,其中包含汇编指令,但您无法读取它。

  • Now运行javap -c A

<代码>H115您可以看到方法调用的汇编生成--> <代码>E116a.printValue();

  • If printValue( )方法是私有的你需要使用javap -c -private a.

  • 你可以使你的printValue( )私有/静态/公共/私有都是静态的。

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

注意:现在请记住,如果我们的调用方法是静态的,则生成invokeStatic程序集;如果它是私有的,则生成invokeSpecial程序集指令;如果它是公共的,则生成invokeVirtual指令。公共方法并不意味着每次生成invokeVirtual指令时都会生成。在super.printValue()的情况下,从A的子类调用是例外情况。也就是说,如果A是B的父类,并且B包含相同的方法printValue(),那么它将生成invokeVirtual(动态),但是如果B中的printValue()将super.printValue()作为其第一个语句,那么即使A的printValue()是公共的,也会生成invokeStatic。

让我们也试试这个:

代码语言:javascript
复制
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测试

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13764238

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档