Method Overloading / Overriding — Specification Deep-Dive¶
JLS §8.4.8 (overriding), §15.12 (method invocation, overload resolution), JVMS §4.3.3 (descriptors), JVMS §5.4.5 (method dispatch), JVMS §6.5 (invoke* opcodes).
1. Where canonical text lives¶
| Topic | Source |
|---|---|
| Method declaration | JLS §8.4 |
| Method signatures | JLS §8.4.2 |
| Override-equivalent signatures | JLS §8.4.2 |
| Overriding rules | JLS §8.4.8 |
| Method invocation | JLS §15.12 |
| Overload resolution | JLS §15.12.2 |
| Most-specific method | JLS §15.12.2.5 |
| Hiding (static) vs overriding | JLS §8.4.8.2 |
| Covariant return | JLS §8.4.8.3 |
| Exception narrowing | JLS §8.4.8.4 |
| Method descriptors | JVMS §4.3.3 |
invokevirtual | JVMS §6.5 |
| Vtable / dispatch | JVMS §5.4.5 |
2. JLS §8.4.2 — override-equivalent signatures¶
Two methods have override-equivalent signatures iff: - They have the same name AND - After type-parameter substitution and erasure, their parameter types match exactly OR - One is a subsignature of the other.
This rule determines whether one method overrides/hides another.
3. JLS §15.12.2 — overload resolution phases¶
When you call e.m(args), the compiler picks one method:
The process to determine the most specific applicable method has three phases: - Phase 1: identify methods applicable by strict invocation. - Phase 2: identify methods applicable by loose invocation. - Phase 3: identify methods applicable by variable arity invocation.
The phases are tried in order. As soon as one phase finds an applicable method, it is selected; the most specific is chosen.
Strict: no boxing, no varargs. Loose: allow boxing/unboxing. Variable arity: allow varargs.
4. JLS §15.12.2.5 — most specific method¶
Method
m1is more specific thanm2if: every argument that's valid form1is also valid form2andm1has stricter parameter types thanm2.
For ambiguity, the compiler errors.
Specifically, for parameter types S of m1 and T of m2: - Reference: S is a subtype of T. - Primitive: S is implicitly convertible to T (widening). - Generic: subtyping rules apply.
5. JLS §8.4.8.1 — when one method overrides another¶
Method m1 declared in class C overrides method m2 declared in class A (or interface A) iff: 1. C is a subtype of A. 2. m1's signature is a subsignature of m2's. 3. m1 is not private. 4. m2 is accessible from C, OR there's an intermediate method m3 such that m1 overrides m3 and m3 overrides m2.
6. JLS §8.4.8.3 — return type compatibility¶
The override's return type must be: - The same primitive type (no widening), OR - A subtype of the parent's return (covariant), OR - The same reference type.
Bridge methods preserve binary compatibility for covariant returns.
7. JLS §8.4.8.4 — throws clause compatibility¶
The override's throws clause must be a subset (in subtype terms) of the parent's:
class Parent { void m() throws IOException { } }
class Child extends Parent {
void m() throws FileNotFoundException { } // OK — narrower
void m() throws Exception { } // ERROR — wider
void m() { } // OK — empty (narrower)
void m() throws RuntimeException { } // OK — unchecked always allowed
}
8. JLS §8.4.8.2 — method hiding (static)¶
A static method
m1declared in classChides methodm2declared in superclassAiff: 1.Cis a subclass ofA. 2.m1's signature is a subsignature ofm2's. 3.m1isstatic.
Hiding is not overriding. Static dispatch picks the method based on declared type, not actual class.
9. JLS §8.4.8 — restrictions¶
The override: - Cannot have weaker access. - Cannot have wider throws. - Cannot be static if parent is instance. - Cannot be final if it overrides.
10. JVMS §4.3.3 — method descriptors¶
Descriptor format:
Type encodings: - B = byte - S = short - I = int - J = long - F = float - D = double - Z = boolean - C = char - V = void (return only) - L<class>; = reference - [<type> = array
int add(int, int) → (II)I
String name() → ()Ljava/lang/String;
void put(Object) → (Ljava/lang/Object;)V
int[] sort(int[]) → ([I)[I
Two methods with different descriptors are different methods, even if names match. This is what enables overloading.
11. JVMS §5.4.5 — method resolution¶
When a methodref is resolved (at link time): 1. Find class containing the method. 2. Search recursively up the class chain. 3. Search interface tables. 4. Bind to the resolved method.
For invokevirtual, the resolved slot is then used at runtime to dispatch to the receiver's actual method.
12. JVMS §6.5 — invoke* opcodes¶
| Opcode | Use | Dispatch |
|---|---|---|
invokevirtual | Instance methods | Vtable |
invokeinterface | Interface methods | Itable |
invokestatic | Static methods | Direct |
invokespecial | Constructors, super, private | Direct |
invokedynamic | Bootstrap-resolved (lambda, indy) | CallSite |
13. Reading order¶
- JLS §8.4.2 — signatures
- JLS §8.4.8 — overriding
- JLS §15.12 — method invocation
- JLS §15.12.2 — overload resolution
- JLS §15.12.2.5 — most specific
- JVMS §4.3.3 — descriptors
- JVMS §5.4.5 — resolution
- JVMS §6.5 — invoke* opcodes
Memorize this: overloading is a JLS §15.12.2 compile-time selection in three phases. Overriding is JLS §8.4.8 with rules on return types, throws, access. Bytecode encodes signatures via descriptors (JVMS §4.3.3). Dispatch is via invokevirtual/invokeinterface/invokestatic/invokespecial based on method kind.