为什么invokeVirtual存在时需要invokeSpecial

Ahm*_*aya 46 java jvm bytecode

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

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

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

Tim*_*ote 36

来自这个网站

如果仔细阅读Java VM Spec,可以很容易地找到答案:

invokespecial和invokevirtual指令之间的区别在于invokevirtual基于对象的类调用方法.invokespecial指令用于调用实例初始化方法以及当前类的超类的私有方法和方法.

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

  • 除非您正在进行超级调用,并且目标类具有ACC_SUPER标志(每个现代类都会这样). (2认同)

Ahm*_*aya 23

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • @wchargin例如,当Superclass是您扩展的库类时,可能会发生这种情况.也许你甚至没有它的源代码.你当然不关心它的私人方法.你很有可能在Subclass中添加一个恰好与Superclass中的私有方法同名的方法. (7认同)
  • 我认为没有充分理由拥有这样的代码.这是[*hidden*](http://docs.oracle.com/javase/tutorial/java/IandI/override.html),如果你这样做,任何好的IDE都会给你一个警告或错误.两个`interestingMethod`签名之间的细微差别足以让读者混淆正在发生的事情. (3认同)
  • 对于其他读者:还请记住,Java 语言具有 JVM 没有的规则和限制。上面是“什么样的源代码可能产生所讨论的字节码”的一个很好的例子,但这并不意味着它是好的软件工程。:-) 就这一点而言,这样的源代码不必是 Java,而只是可以编译为 JVM 字节码的某种语言。 (2认同)