理解动态多态字节码:Java字节码新手的Dispatch类解析请求
Hey there! Let's break this down step by step since you're new to Java bytecode. First, let's start with what the Dispatch.java source code must look like (we can reverse-engineer it directly from the bytecode you shared), then we'll walk through each line of the bytecode to connect the dots.
Inferred Dispatch.java Source Code
This is the code that would compile to the bytecode you provided:
class A { public void run() { // The actual implementation doesn't affect our bytecode analysis } } class B extends A { // B inherits run() from A, or could override it—either way, dynamic dispatch handles it } public class Dispatch { // Implicit default constructor (compiler adds this since we don't define one) public Dispatch() { super(); } public static void main(String[] args) { B b = new B(); b.run(); } }
Let's Analyze the Dispatch Class Bytecode
First, let's look at the constructor for the Dispatch class:
Compiled from "Dispatch.java"
class Dispatch {
Dispatch();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
Here's what each line does:
aload_0: Pushes thethisreference (stored in local variable 0) onto the operand stack. Every non-static method automatically getsthisas its first local variable.invokespecial #1: Calls the superclass (Object) constructor. All Java constructors must call their parent's constructor first (either explicitly or implicitly), andinvokespecialis used for direct, non-virtual calls to constructors or private methods. The#1points to an entry in the class's constant pool that referencesObject's no-arg constructor.return: Exits the constructor and returns control to the caller.
Now the main() Method Bytecode (The Interesting Part!)
This is where the dynamic dispatch happens—let's break down each line:
public static void main(java.lang.String[]);
Code:
0: new #2 // class B
3: dup
4: invokespecial #3 // Method B."":()V
7: astore_1
8: aload_1
9: invokevirtual #4 // Method A.run:()V
12: return
Line-by-line breakdown:
new #2: Creates a new, uninitialized instance of classB. This pushes a reference to the uninitialized object onto the operand stack. The#2is a constant pool entry pointing to theBclass.dup: Duplicates the top value on the operand stack (the uninitializedBreference). We need two copies because the constructor call will consume one, and we need the other to store in a local variable.invokespecial #3: CallsB's no-arg constructor to initialize the object. This consumes one copy of theBreference from the stack, leaving the initialized reference ready to store.astore_1: Stores the fully initializedBreference into local variable 1 (local variable 0 is theargsparameter passed tomain).aload_1: Pushes theBreference from local variable 1 back onto the operand stack so we can call a method on it.invokevirtual #4: This is the magic of dynamic dispatch! Even though the bytecode saysMethod A.run:()V, the JVM will look at the runtime type of the object (which isB, notA) and call the appropriaterun()method. IfBoverridesrun(), that's the one that executes; if not, it falls back toA's implementation. This is how Java achieves polymorphism.return: Exits themainmethod and returns control to the JVM.
Key Takeaway
The invokevirtual instruction is what makes Java's polymorphism work. It doesn't just call the method defined in the declared type (A here)—it resolves the method based on the actual object type at runtime. That's why this example is called Dispatch!
内容的提问来源于stack exchange,提问作者ecdhe

