java虚拟机中,将符号引用转换为调用方法的直接引用与方法绑定机制相关。
静态链接:
当一个字节码文件被装载到jvm内部时,如果被调用的目标方法在编译器可知,且运行期保持不变时。这种情况下将调用方法的符号引用转换为直接引用的过程称之为静态链接。
动态链接:
如果被调用的方法在编译期无法被确定下来,也就是说,只能够在程序运行期将调用方法的符号引用转换为直接引用,由于这种引用转换过程具备动态性,因此也就被称之为动态链接;
对应的方法绑定机制为:早期绑定和晚期绑定
早期绑定:
早期绑定就是指被调用的目标方法如果在编译期可知,且运行期保持不变时,即可将这个方法与所属的类型进行绑定,这样一来,由于明确了被调用的目标方法究竟是哪一个,因此也可以使用静态链接的方式将符号引用转换为直接引用
晚期绑定:
如果被调用的方法在编译期无法被确定下来,只能够在程序运行期根据实际的类型绑定相关的方法,这种绑定方式也被称之为晚期绑定
class Animal{ public void eat(){ System.out.println("动物进食"); } } interface Huntable{ void hunt(); } class Dog extends Animal implements Huntable{ @Override public void eat() { System.out.println("狗吃骨头"); } @Override public void hunt() { System.out.println("捕食耗子,多管闲事"); } } class Cat extends Animal implements Huntable{ public Cat(){ super();//表现为:早期绑定 } public Cat(String name){ this();//表现为:早期绑定 } @Override public void eat() { super.eat();//表现为:早期绑定 System.out.println("猫吃鱼"); } @Override public void hunt() { System.out.println("捕食耗子,天经地义"); } } public class AnimalTest { public void showAnimal(Animal animal){ animal.eat();//表现为:晚期绑定 } public void showHunt(Huntable h){ h.hunt();//表现为:晚期绑定 } }
虚方法和非虚方法
非虚方法:
如果方法在编译期就确定了具体的调用版本,这个版本在运行时是不可变的,这样的方法叫做非虚方法;
包括:静态方法,私有方法,final方法,实例构造器,父类方法都是非虚方法,其他方法称虚方法
虚拟机中提供了一下几种方法调用指令:
普通调用指令:
1.invokestatic:调用静态方法,解析阶段确定唯一方法版本
2.invokespecila:调用<init>方法,私有及父类方法,解析阶段确定唯一方法版本
3.invokevirtual:调用所有虚方法
4.invokeinterface:调用接口方法
动态调用指令:
5.invokedynimic:动态解析出需要调用的方法,然后执行
前四条指令固化在虚拟机内部,方法的调用执行不可认为干预,而invokedynamic指令则支持由用户确定方法版本.其中invokestatic指令和invokespecial指令调用的方法称为非虚方法,其余的(final修饰的方法除外)称为虚方法.
/** * 解析调用中非虚方法、虚方法的测试 * * invokestatic指令和invokespecial指令调用的方法称为非虚方法 * @author shkstart * @create 2020 下午 12:07 */ class Father { public Father() { System.out.println("father的构造器"); } public static void showStatic(String str) { System.out.println("father " + str); } public final void showFinal() { System.out.println("father show final"); } public void showCommon() { System.out.println("father 普通方法"); } } public class Son extends Father { public Son() { //invokespecial super(); } public Son(int age) { //invokespecial this(); } //不是重写的父类的静态方法,因为静态方法不能被重写! public static void showStatic(String str) { System.out.println("son " + str); } private void showPrivate(String str) { System.out.println("son private" + str); } public void show() { //invokestatic showStatic("atguigu.com"); //invokestatic super.showStatic("good!"); //invokespecial showPrivate("hello!"); //invokespecial super.showCommon(); //invokevirtual showFinal();//因为此方法声明有final,不能被子类重写,所以也认为此方法是非虚方法。 //虚方法如下: //invokevirtual showCommon(); info(); MethodInterface in = null; //invokeinterface in.methodA(); } public void info(){ } public void display(Father f){ f.showCommon(); } public static void main(String[] args) { Son so = new Son(); so.show(); } } interface MethodInterface{ void methodA(); }