Java的动态绑定的原理

  1. 类加载 当 JVM 首次遇到一个新的类(例如,通过创建一个该类的对象或者调用该类的方法),它会进行类加载。类加载包括加载、链接和初始化三个阶段:

  2. 加载:JVM 的类加载器(ClassLoader)查找类定义(通常是.class文件),并将其加载到内存中。

  3. 链接:链接阶段包括验证类定义的正确性、准备(为静态变量分配内存并设置默认初始值)和-解析(将常量池中的符号引用转换为直接引用)。
  4. 初始化:在这个阶段,JVM 执行类构造器 (),这涉及到静态变量的初始化和静态初始化块的执行。
  5. 方法表(vtable)和接口表(itable) 在链接阶段的解析过程中,JVM 会为每个类构建两个重要的数据结构:

    • 方法表(vtable):对于非抽象类,JVM 会创建一个方法表,它包含了类的所有实例方法的直接引用。如果一个类重写了其父类的方法,那么该方法在方法表中的方法引用会指向子类版本的实现方法(在方法区)
    • 接口表(itable):对于实现了接口的类,JVM 会创建一个接口表,它包含了接口方法的直接引用。如果一个类实现了接口的多个方法,那么这些方法的引用会被存储在接口表中。
    • 动态方法分派 当通过父类或接口的引用调用一个方法时,JVM 使用动态方法分派来确定调用哪个方法:

    • 对于虚方法调用(即通过父类或接口的引用调用的方法),JVM 会查找对象的实际类型,并在该类型的方法表(vtable)中查找对应的方法进行调用。

    • 对于接口方法调用,JVM 会查找对象的实际类型所对应的接口表(itable)中的实现。
    • 运行时类型检查 在运行时,JVM 会进行类型检查,以确保调用的方法与对象的实际类型兼容。如果调用的方法在对象的实际类型中不存在,JVM 会抛出 AbstractMethodError 或其他相关异常。
  6. 即时编译器(JIT) 现代 JVM 通常包含一个即时编译器(JIT),它会将热点代码(经常执行的代码)编译为本地机器代码以提高性能。在 JIT 编译过程中,编译器可能会进行进一步的优化,包括内联和去虚拟化,以消除虚方法调用的开销。

通过这些机制,JVM 能够在运行时准确地找到并调用 Dog 类的方法表中的适当方法,从而实现多态性。

Father s=new Son()不能静态绑定方法是因为编译时对象包括对象头还没有生成,无法去找相应对象头中的方法表或者是接口表; 静态绑定(也称为早期绑定或编译时绑定)发生在编译时。这意味着编译器在编译程序时就确定了方法调用的目标方法。静态绑定通常用于如私有方法、静态方法、final方法等,因为这些方法不能被覆盖

回到页面顶部