多態是面向對象核心特性,分為編譯期多態(重載)和運行期多態(覆蓋)。本文通過字節碼視角解析 javac 如何為這兩種多態生成調用指令,揭示 JVM 方法調用的底層機制。
class A {
public void m(int i) { System.out.println("int"); }
public void m(String s) { System.out.println("string"); } // 重載
}
class B extends A {
@Override
public void m(int i) { System.out.println("overridden int"); } // 覆蓋
}
public class PolymorphismDemo {
public static void main(String[] args) {
A a = new A();
a.m(1); // 調用 A.m(int)
a.m("abc"); // 調用 A.m(String)
A b = new B(); // 多態:引用類型 A,實際類型 B
b.m(1234); // 調用 B.m(int) —— 動態分發
}
}
invokevirtual 指令,常量池存儲方法符號引用(類名、方法名、描述符)。a.m(1) → 解析為 A.m(int);a.m("abc") → 解析為 A.m(String)。long 調用 m(int) 需顯式轉型)。b.m(1234):引用類型 A,實際類型 B。JVM 在 B 的方法表中查找 m(int),找到 B.m(int) 執行。| 指令 | 用途 | 綁定類型 | 典型場景 |
|---|---|---|---|
invokestatic |
靜態方法 | 靜態 | Math.max() |
invokespecial |
私有方法、構造器、父類方法 | 靜態 | super.toString() |
invokevirtual |
普通實例方法 | 動態 | 多態調用 obj.method() |
invokeinterface |
接口方法 | 動態 | list.size() |

Klass 元數據,包含方法表、常量池指針等。invokespecial/invokestatic,不參與動態分發。invokedynamic(JDK 7+):支持動態語言,Lambda 表達式底層實現。src/hotspot/share/oops/method.hpp 方法表實現