一 虚方法和非虚方法
如果方法在编译期就确定了具体的调用版本,这个版本在运行时是不可变的。这样的方法称为非虚方法。
静态方法、私有方法、final方法、实例构造器、父类方法都是非虚方法。
其他方法称为虚方法。
子类对象的多态的使用前提
- 类的继承关系
- 方法的重写
二 虚拟机中提供了以下几条方法调用指令
1 普通调用指令
-
invokestatic:调用静态方法,解析阶段确定唯一方法版本。它对应的是非虚方法。
-
invokespecial:调用<init>方法、私有及父类方法,解析阶段确定唯一方法版本。它对应的是非虚方法。
-
invokevirtual:调用所有虚方法。final 修饰的方法是非虚方法。final 修饰除外的方法是虚方法。
-
invokeinterface:调用接口方法。它对应的是虚方法。
2 动态调用指令
-
invokedynamic:动态解析出需要调用的方法,然后执行。
前四条指令固化在虚拟机内部,方法的调用执行不可人为干预,而 invokedynamic 指令则支持由用户确定方法版本。其中 invokestatic 指令 和invokespecial 指令调用的方法称为非虚方法,其余的(final修饰的除外)称为虚方法。
三 实战
1 代码
/**
* 解析调用中非虚方法、虚方法的测试
* invokestatic 指令和 invokespecial 指令调用的方法称为非虚方法
*/
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();
}
2 测试结果
father的构造器
son atguigu.com
father good!
son privatehello!
father 普通方法
father show final
father 普通方法
Exception in thread "main" java.lang.NullPointerException
at com.atguigu.java2.Son.show(Son.java:65)
at com.atguigu.java2.Son.main(Son.java:77)