Method invocation connects Java source-level calls to runtime method selection, stack frame creation, return behavior, and exception unwinding.

Learning Question

When Java code calls a method, how does the JVM know what actually runs?

At the source level, a method call looks like one operation:

service.process(order);

At runtime, the JVM must evaluate the receiver and arguments, select the target method according to invocation rules, create a frame for the call, execute the method, and return or unwind through exceptions.

The first mental model is:

A Java method call is runtime dispatch plus frame-based execution.

Invocation Instructions

JVM bytecode has different invocation instructions for different call shapes.

Common categories include:

Instruction CategoryTypical Meaning
invokestaticCall a static method
invokevirtualCall an instance method with virtual dispatch
invokeinterfaceCall through an interface type
invokespecialCall constructors, private methods, and selected superclass methods
invokedynamicLet a bootstrap mechanism define call behavior dynamically

The source expression does not carry all runtime details by itself. The compiler emits bytecode that says which invocation mechanism applies. The JVM then resolves symbolic references and applies the relevant dispatch rules.

Overloading vs. Overriding

Overloading and overriding are often mixed together, but they happen at different levels.

Overloading is resolved at compile time based on the declared types and method signatures available to the compiler.

Overriding is selected at runtime for virtual method calls based on the actual class of the receiver object.

For example:

Animal animal = new Dog();
animal.speak();

If speak is a virtual instance method and Dog overrides it, the runtime receiver is a Dog, so the Dog implementation can run even though the variable type is Animal.

This is dynamic dispatch.

Null Receivers

For an instance method call, the receiver must be a real object reference.

If the receiver is null, the JVM cannot dispatch to an instance method and a NullPointerException is thrown.

This failure happens before application method body execution. The method was not entered because there was no object to receive the call.

Frame Creation and Return

Once the target method is selected, the JVM creates a new stack frame for that invocation on the current thread’s Java stack.

Arguments are placed into the callee’s local variable slots according to the method descriptor. The method executes using its own frame. When it returns normally, its return value is passed back to the caller and the callee frame is removed.

This is why each call has separate local execution state even when the same method is called recursively or concurrently by multiple threads.

Exceptions

An exception changes the normal return path.

When code throws an exception, the JVM looks for a matching exception handler in the current method. If none exists, the current frame is popped and the search continues in the caller’s frame. This continues until a matching handler is found or the thread exits due to an uncaught exception.

This process is stack unwinding.

A stack trace attached to an exception records the call path at the point the throwable captured its stack information. It is a diagnostic view of how execution reached the failure, not a complete history of the entire program.

Why This Matters

Method invocation explains several practical behaviors:

  • A call through an interface can run different implementations depending on the receiver object.
  • A dependency version mismatch can produce NoSuchMethodError when a symbolic method reference cannot be resolved against the loaded runtime class.
  • A NullPointerException on a method call means the receiver was missing before the method body ran.
  • An exception stack trace follows frame unwinding and handler search rules.
  • JIT optimization can inline method calls, but the Java-visible method semantics must remain valid.

Core Mental Model

Keep these boundaries separate:

  • The compiler chooses the bytecode invocation category.
  • The JVM resolves symbolic method references against loaded classes.
  • Virtual and interface calls can dispatch based on the receiver’s runtime class.
  • A successful call creates a new frame on the current thread’s stack.
  • Exceptions search for handlers and unwind frames when handlers are not found.

Final Summary

Java method calls are not just source-level jumps.

They are bytecode-level invocations that resolve and dispatch methods, create stack frames, return values, and unwind frames when exceptions change the control path.