符号引用到直接引用
由于 Java 的编译没有C C++ 编译过程中的链接阶段,所以 Class 文件中储存的只是符号引用,等到了在运行时才通过符号引用定位到方法区中方法代码在内存布局中的位置--直接引用。
符号引用到直接引用的替换又涉及两种方式。一种是解析,另一种是分派。解析发生在类加载的解析阶段,分派发生在编译或方法调用阶段。
解析
在类加载的解析阶段会把满足「编译期可知,运行期不可变」的方法的符号引用替换为指向方法区的直接引用,不会延迟到运行时再去完成。
满足编译期可知,运行期不可变的方法有:构造函数、私有方法、静态方法、final修饰的方法。不满足上述条件的方法的符号引用替换发生在方法调用期间。
分派 Dispatch
多态的实现原理
变量类型
理解分派之前,需要先看两个类型概念。
比如:Object obj = new String("");
静态类型
定义变量时,声明的类型。比如这里 obj 的静态类型就是 Object。静态类型在编译期的编译器就能知道。
实际类型
变量赋值时的实际类型。比如这里 obj 的实际类型就是 String。实际类型在编译期的编译器是不可知的。
静态分派
根据变量的「静态类型(外观类型)」匹配调用方法的过程称为静态分派。发生的场景为方法重载。
如下代码:
public class StaticDispatch {
static abstract class Human { }
static class Man extends Human { }
static class Woman extends Human { }
static class Child extends Human { }
public void say(Human human) {
System.out.println("human");
}
public void say(Man man) {
System.out.println("man");
}
public void say(Woman woman) {
System.out.println("woman");
}
public void say(Child child) {
System.out.println("child");
}
}
public static void main(String[] args) {
Human man = new Man();
Human woman = new Woman();
Human child = new Child();
StaticDispatch dispatch = new StaticDispatch();
dispatch.say(man);
dispatch.say(woman);
dispatch.say(child);
}










