invokevirtual字节码
在具体举例描述之前先描述invokevirtual字节码工作过程
找到操作数栈顶的第一个元素所指向的对象的实际类型,记作C。
在类型C中找到与常量中的描述符和简单名称都相符的方法。
如果找到则进行访问权限的校验。
如果通过则返回这个方法的直接引用,查询结束;
如果不通过,则返回java.lang.IllegalAccessError异常。
否则,按继承关系从下向上对C的各个父类进行第2步操作。
如果没有找到合适的方法,抛出AbstractMethodError异常。
以下判断均基于该字节码
invokevirtual字节码.png
分派
Java语言的静态分派属于多分派类型;Java语言的动态分派属于单分派类型
静态分派是由编译器指定的,编译器虽然能确定出方法的重载版本,但在很多情况下这个重载版本并不是"唯一的"。
有显式的静态类型时,通过静态类型确认执行哪个重载方法
没有显式的静态类型时,只能通过语言上的规则去理解和推断
类型变化简单描述
示例代码: Human man = new Man();
// "Human"称为变量的静态类型/外观类型 “Man” 则称为变量的实际类型
// 实际类型变化
Human man = new Man();
man = new Woman();
// 静态类型变化
sr.sayHello((Man) man);
sr.sayHello((Woman) man)
静态分派
可以理解为方法的入参与静态分派有关,静态分派决定了在方法
重载
时使用哪个运行。
public class StaticDispatch {
public void sayHello(Human guy) { System.out.println(1); }
public void sayHello(Man guy) { System.out.println(2); }
public void sayHello(Woman guy) { System.out.println(3); }
// 输出结果为 1 2 1 3
public static void main(String[] args) {
Human man = new Man();
Human woman = new Woman();
StaticDispatch sd = new StaticDispatch();
sd.sayHello(man);
sd.sayHello((Man) man);
sd.sayHello(woman);
sd.sayHello((Woman) woman);
}
}
abstract class Human {}
class Man extends Human {}
class Woman extends Human {}
静态分派代码字节码.png
动态分派
对
invokevirtual字节码
含义的体现,动态分派决定了在方法重写
时使用哪个运行。
public class DynamicDispatch {
public static void main(String[] args) {
Human man = new Man();
man.sayHello();
man = new Woman();
man.sayHello();
Human woman = new Woman();
woman.sayHello();
}
}
abstract class Human {
protected abstract void sayHello();
}
class Man extends Human {
@Override
protected void sayHello() { System.out.println("man say Hello!"); }
}
class Woman extends Human {
@Override
protected void sayHello() { System.out.println("woman say Hello!"); }
}
动态分派代码字节码.png
Java 自带类型的方法重载
这个示例就是没有显式的静态类型,所以只能通过语言上的规则去理解和推断
测试方法是:以
char-> int -> long -> float -> double -> 包装类 ->Serializable -> Object -> 可变长参数
的顺序尝试注释目标方法,然后运行看输出结果。
如果在idea中则不需要运行测试,被调用的方法会高亮,通过观察就可以知道结果。
public class Overload {
public static void sayHello(Object arg) {
System.out.println("Object");
}
public static void sayHello(int arg) {
System.out.println("int");
}
public static void sayHello(long arg) {
System.out.println("long");
}
public static void sayHello(float arg) {
System.out.println("float");
}
public static void sayHello(double arg) {
System.out.println("double");
}
public static void sayHello(char arg) {
System.out.println("char");
}
public static void sayHello(char... arg) {
System.out.println("char");
}
public static void sayHello(Character arg) {
System.out.println("Character");
}
public static void sayHello(Integer arg) {
System.out.println("Character");
}
public static void sayHello(Serializable arg) {
System.out.println("Serializable");
}
public static void main(String[] args) {
sayHello('c');
}
}
网友评论