What is the difference between static (early) binding and dynamic (late) binding in Java, and when does each happen?
answer
- Static = compile time + declared type; Dynamic = run time + actual object type
- Methods dispatch on runtime type; fields and statics on compile-time type
- Overload picked at compile time; override picked at run time
- invokevirtual/invokeinterface = dynamic; invokestatic/invokespecial = static
- final/private/static methods are statically bound
basics
~20 sBinding is how a call is matched to the actual method or variable. Static binding is decided at compile time (overloaded methods, static methods, fields). Dynamic binding is decided at run time based on the real object type, which is how overridden instance methods work.
solid answer
~40 sBinding is the process of connecting a method or field reference in code to the concrete member that actually runs or is read. Java does it in two ways. Static (early) binding is resolved by the compiler using the declared (compile-time) type of the reference; it applies to fields, static methods, private methods, final methods, and overload selection. Dynamic (late) binding is resolved at run time using the actual class of the object the reference points to; it applies to ordinary (virtual) overridden instance methods via the invokevirtual/invokeinterface mechanism. So `Animal a = new Dog(); a.sound();` runs Dog's override because the method is dynamically bound, but a field access `a.legs` reads Animal's field because fields are statically bound. This split is the engine behind runtime polymorphism.
go deeper
Knows static binding is at compile time and dynamic binding is at run time, and that overridden instance methods use the actual object's type.
Can list what is statically bound (fields, static/private/final methods, overload choice) vs dynamically bound (virtual instance methods) and explain the field-vs-method gotcha.
Explains the compile-time vs runtime type distinction precisely, names invokevirtual/invokeinterface vs invokestatic/invokespecial, and connects dynamic binding to runtime polymorphism.
Discusses vtable/method-table dispatch, JIT devirtualization (monomorphic/bimorphic inlining), and the performance and design rationale for the static/dynamic split.
## What "binding" means When you write `obj.doThing()` or read `obj.value`, the compiler and JVM must figure out *which* concrete method body runs or *which* field is read. Connecting that name in your source code to a concrete member is called **binding**. Java does this in two different moments. ## Two key types in play Every reference variable has two types: - **Compile-time type (declared/static type):** the type written in the variable's declaration. In `Animal a = new Dog();` the compile-time type of `a` is `Animal`. - **Runtime type (dynamic/actual type):** the class of the object actually created on the heap — here `Dog`. Which type is used to resolve the member is exactly what distinguishes the two bindings. ## Static (early) binding **Static binding** (also called *early binding*) happens at **compile time**, using the **compile-time type** of the reference. The decision is baked into the bytecode and never changes at run time. It applies to: - **Fields** — `a.legs` reads the field declared in the compile-time type. Fields are *never* polymorphic. - **`static` methods** — resolved by the declared type; redeclaring one in a subclass is *hiding*, not overriding. - **`private` methods** — not visible to subclasses, so no override is possible. - **`final` methods** — cannot be overridden, so the target is fixed. - **Overload resolution** — *which* overloaded signature (e.g. `print(int)` vs `print(long)`) is chosen is always a compile-time decision based on the static types of the arguments. A non-virtual call in JVM terms is one the JVM does not have to look up per-object; it uses `invokestatic` or `invokespecial`. ## Dynamic (late) binding **Dynamic binding** (also called *late binding* or *virtual invocation*) happens at **run time**, using the **runtime type** of the object. It applies to ordinary, overridable instance methods. The compiler only records the method's name and descriptor (its signature); the JVM, at the moment of the call, looks up the actual object's class and invokes the most-derived override. This is implemented with the `invokevirtual` bytecode (or `invokeinterface` for interface-typed references), typically via a per-class method table (vtable) the JVM walks. This is the mechanism that makes **runtime polymorphism** work: `Animal a = new Dog(); a.sound();` prints the Dog sound even though `a` is declared as `Animal`. ## The classic gotcha: methods vs fields ```java class Animal { int legs = 4; String kind() { return "animal"; } } class Dog extends Animal { int legs = 4; String kind() { return "dog"; } } Animal a = new Dog(); a.kind(); // "dog" -> method: dynamic binding, uses runtime type Dog a.legs; // Animal's legs -> field: static binding, uses compile-time type Animal ``` Methods dispatch on the runtime type; field *access* and `static` method *invocation* resolve on the compile-time type. Mixing these up is a very common interview trap. ## Why Java made this choice Virtual dispatch for instance methods is what lets subclasses specialize behavior — the core of OOP. Static binding for fields and statics keeps them fast and predictable (no per-object lookup) and avoids surprising shadowing semantics. The cost of dynamic dispatch is a small indirection, which modern JITs largely erase via inlining and monomorphic/bimorphic call-site optimization.
- Given `Animal a = new Dog();`, why does `a.kind()` use Dog but `a.legs` use Animal?Instance methods are dynamically bound on the runtime type (Dog), so the override runs. Field access is statically bound on the compile-time type (Animal), so it reads Animal's field. Fields are never polymorphic.
- Are static methods dynamically dispatched?No. A static method redeclared in a subclass is hidden, not overridden, and is resolved at compile time by the reference's declared type (invokestatic).
saying these in an interview costs you the question
- Saying fields are polymorphic / that `a.legs` uses the runtime type
- Claiming static methods are overridden and dynamically dispatched (they are hidden, statically bound)
- Confusing overloading (compile-time/static) with overriding (run-time/dynamic)
- Saying all method calls in Java are dynamically bound (private/final/static are not)