java 存在 invokeVirtual 时为什么需要 invokeSpecial
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13764238/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why invokeSpecial is needed when invokeVirtual exists
提问by Ahmet Karakaya
There are three opcodes to invoke Java methods. It is clear that invokeStatic is just for static method invocation.
有三种操作码可以调用 Java 方法。很明显,invokeStatic 只是用于静态方法调用。
As far as I know invokespecial is used when invoking constructor and private methods. So, do we need to differenticate private and public method invocation at run time? It could be invoked with same opcode say invokevirtual?
据我所知,在调用构造函数和私有方法时使用 invokespecial。那么,我们需要在运行时区分私有和公共方法调用吗?它可以用相同的操作码调用,比如 invokevirtual?
Does JVM deals with private and public method definition? As far as I know public and private keywords is just needed at development phase for encapsulation?
JVM 是否处理私有和公共方法定义?据我所知,在开发阶段只需要 public 和 private 关键字进行封装?
采纳答案by Ahmet Karakaya
http://www.artima.com/underthehood/invocationP.htmlThe link above gives valuable examples clearly which addresing my question.
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();
}
}
When you invoke main() in Subclass as defined above, it must print "Superclass's interesting method." If invokevirtual were used, it would print "Subclass's interesting method." Why? Because the virtual machine would choose the interestingMethod() to call based on the actual class of the object, which is Subclass. So it will use Subclass's interestingMethod(). On the other hand, with invokespecial the virtual machine will select the method based on the type of the reference, so Superclass's version of interestingMethod() will be invoked.
当您在子类中调用上面定义的 main() 时,它必须打印“超类的有趣方法”。如果使用 invokevirtual,它将打印“子类的有趣方法”。为什么?因为虚拟机会根据对象的实际类,即子类,选择调用interestingMethod()。所以它会使用子类的interestingMethod()。另一方面,使用 invokespecial 虚拟机将根据引用的类型选择方法,因此将调用超类版本的interestingMethod()。
回答by Tim Pote
From 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.
In other words, invokespecial is used to call methods without concern for dynamic binding, in order to invoke the particular class' version of a method.
如果仔细阅读 Java VM 规范,就很容易找到答案:
invokespecial 和 invokevirtual 指令的区别在于 invokevirtual 根据对象的类调用方法。invokespecial 指令用于调用实例初始化方法以及当前类的超类的私有方法和方法。
换句话说,invokespecial 用于调用方法而不考虑动态绑定,以便调用特定类的方法版本。
回答by Maddy
Thanks for reading out that explanation: Please don't forget to upvote if it helps you out to identify assembly instruction creation during method call Here I am explaining static vs dynamic binding.
感谢您阅读该解释:如果它可以帮助您在方法调用期间识别汇编指令创建,请不要忘记点赞这里我将解释静态绑定与动态绑定。
First of all I am going to tell you that invokeStatic, invokeSpecial, invokeVirtual, invokeInterfaceetc are the assembly instructions which are generate by the compiler after compilation process. As we all knows that we got a .class file format after compilation and we can't read it out. But java provide a tool for that named "javap".
首先我要告诉你,invokeStatic、invokeSpecial、invokeVirtual、invokeInterface等是编译器在编译后生成的汇编指令。众所周知,我们编译后得到了一个.class文件格式,我们无法读取它。但是 java 为名为"javap" 的那个提供了一个工具。
We can read out our .class file assembly instructions by using javap command. By default we can't see private method assembly instructions so we need to use -private with it. Below are the commands to see java compiler generated assembly instructions:
我们可以使用 javap 命令读出我们的 .class 文件汇编指令。默认情况下,我们看不到私有方法汇编指令,因此我们需要将 -private 与它一起使用。下面是查看java编译器生成的汇编指令的命令:
Imaging you have A.java class
class A { public void printValue() { System.out.println("Inside A"); }
public static void callMethod(A a) { a.printValue(); } }
open cmd prompt and go to the folder which contains that java file A.java.
run javac A.java.
Now A.class file is generated which contains assembly instructions but you can't read it.
Now run javap -c A
You can see assembly generation for your method call --> a.printValue();
If printValue( ) method is private you need to use javap -c -private A .
You can make your printValue( ) private / static / public / private static both.
One more thing to keep in mind that first compiler check the object on which the method is getting called. Then find its Class Type and found that method in that class if available or not.
想象你有 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。
现在生成了 A.class 文件,其中包含汇编指令,但您无法读取它。
现在运行 javap -c A
你可以看到你的方法调用的程序集生成 --> a.printValue();
如果 printValue( ) 方法是私有的,则需要使用 javap -c -private A 。
您可以将您的 printValue( ) 设为私有/静态/公共/私有静态。
要记住的另一件事是,首先编译器会检查调用该方法的对象。然后找到它的类类型并在该类中找到该方法(如果可用或不可用)。
Note :Now keep in mind that if our calling method is static then invokeStatic assembly is generated, if its private then invokeSpecial assembly instruction is generated and if its public then invokeVirtual instruction is generated. public method never mean that every time invokeVirtual instruction is generated. In case of super.printValue() call from the subclass of A is exceptional case. i.e. if A is parent class for B and B contains the same method printValue() then it will generate invokeVirtual(dynamic) but if printValue() in B have super.printValue() as its first statement then invokeStatic is generated even if printValue() of A is public.
注意:现在请记住,如果我们的调用方法是静态的,则生成 invokeStatic 程序集,如果是私有的,则生成 invokeSpecial 汇编指令,如果是公共的,则生成 invokeVirtual 指令。公共方法绝不意味着每次生成 invokeVirtual 指令。如果来自 A 的子类的 super.printValue() 调用是例外情况。即如果 A 是 B 的父类并且 B 包含相同的方法 printValue() 那么它将生成 invokeVirtual(dynamic) 但是如果 B 中的 printValue() 将 super.printValue() 作为它的第一个语句,那么即使 printValue() 也会生成 invokeStatic ) 的 A 是公开的。
Let's try this too:
让我们也试试这个:
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
}
}
--> save it by Test.java --> run javac Test.java --> javap -c -private Test
--> 通过 Test.java 保存 --> 运行 javac Test.java --> javap -c -private Test