重载可以在编译期确定调用的方法。
在 Class 文件内部,方法的符号引用是根据方法名称、参数来区分的,对编译器来说重载方法跟其他方法一样,都是不同的方法而已。
而 Java 的重载是根据静态类型来确定方法,所以可以在编译期就能指定调用的方法。
静态类型 & 实际类型:
如,
SuperClass obj = new SubClass();
语句中,前面的「 SuperClass 」是静态类型,后面的「 SubClass 」是实际类型。变量的静态类型是不可变的,编译时可知的,但是实际类型是运行时才能确定。
例:
public static void main(String[] args) { B b = new B(); f(b); // b A c = new C(); f(c); // 静态类型是A,所以输出a } static void f(C c) { System.out.println("c"); } static void f(B b) { System.out.println("b"); } static void f(A a) { System.out.println("a"); } static class A {} static class B extends A {} static class C extends A {}
重写在运行时根据实际类型来选择方法。
每个类在方法区有它的虚方法表,存放着各方法的实际入口地址。JVM 在执行 invokevirtual 时(final 方法除外),会从实际类型的虚方法表查询(没有会继续查询父类的虚方法表)。
类似的,invokeinterface 执行时会用到接口方法表。
方法表一般在类加载-连接阶段进行初始化,准备了类的变量初始值后,JVM 会把该类的方法表也初始化完毕。
注:invokestatic、invokespecial、final 方法,都能在编译期确定方法,所以 JVM 会在类加载-解析阶段,把这些方法的符号引用替换成直接引用。(final 方法是用 invokevirtual 执行的,因为不能被重写,所以编译时就能确定)
来源:博客园
作者:dmsdus
链接:https://www.cnblogs.com/dmsdus/p/11461535.html