How do the modifiers in a method header (static, final, abstract, synchronized, access) shape what the method is and how it is dispatched, and what tensions arise when combining them?
answer
- Access (who) vs non-access (nature/dispatch)
- static/private/final → non-virtual (static-bound); else virtual dispatch
- static methods are hidden, not overridden (no @Override)
- abstract conflicts with final/static/private/synchronized/native
- synchronized = lock (this, or Class for static); keep it out of the contract
basics
~20 sModifiers change a method's nature: static means it belongs to the class not an instance; abstract means no body; final means it can't be overridden; synchronized adds locking; access modifiers control visibility. Some combinations (like abstract final or abstract static) are illegal because they contradict each other.
solid answer
~50 sMethod-header modifiers fall into access (public/protected/private/default) and non-access (static, final, abstract, synchronized, native, strictfp). They are not independent knobs — several determine dispatch and lifecycle. `static` binds the call to the compile-time type (no virtual dispatch; static methods are hidden, not overridden); instance methods are virtually dispatched unless `private`, `static`, or `final`, which make them non-virtual. `abstract` says there is no body and forces subclass implementation, so it is incompatible with `final`, `static`, `private`, and `synchronized` (each of which presumes or forbids the very overriding abstract requires). `final` locks the implementation as a design/security guarantee and enables inlining. `synchronized` is an implementation detail that acquires the instance or class monitor and pointedly should not leak into the interface contract. The design lesson: modifiers encode intent about extensibility and concurrency, and illegal combinations are the compiler enforcing semantic contradictions.
go deeper
Recognises the common modifiers and roughly what static/private/public mean.
Knows static methods are hidden not overridden, final prevents overriding, abstract has no body, and access controls visibility.
Explains which modifiers opt out of virtual dispatch, the legal-combination rules, and that synchronized's lock target differs for static vs instance methods.
Reads a header as an extensibility/concurrency contract: chooses final/abstract deliberately for design and security, keeps synchronization out of the public contract, and reasons about dispatch, inlining, and substitutability implications of each modifier choice.
## The two families of modifiers - **Access modifiers** — `public`, `protected`, default/package-private (no keyword), `private`. They control *who can call* the method and, indirectly, who can *override* it. - **Non-access modifiers** — `static`, `final`, `abstract`, `synchronized`, `native`, `strictfp`, plus `default` (interface methods). They change the method's *nature*, *dispatch*, or *lifecycle*. ## How modifiers govern dispatch (the core senior/principal insight) Java uses **dynamic (virtual) dispatch** for instance methods: the actual method run is chosen by the object's runtime type. But three modifiers opt a method *out* of virtual dispatch, binding it statically at compile time: - **`static`** — belongs to the class; resolved by the *compile-time* type of the reference. Static methods are **hidden**, not overridden; `@Override` is illegal on them. - **`private`** — not visible to subclasses, so it cannot be overridden; bound statically. - **`final`** — explicitly forbids overriding, so the compiler/JIT may bind/inline it directly. Everything else (a normal `public`/`protected` instance method) is virtually dispatched. Understanding this is what lets you reason about whether a subclass can change behaviour. ## abstract: the 'no body' modifier and its incompatibilities `abstract` declares a method with **no body**; the class must itself be `abstract`, and a concrete subclass must implement it. Because its entire purpose is *to be overridden*, it conflicts with anything that prevents or bypasses overriding: - `abstract` + `final` → contradiction (must override vs cannot override) — **illegal**. - `abstract` + `static` → static methods aren't overridden (they're hidden) and have no instance to dispatch on — **illegal**. - `abstract` + `private` → private isn't visible to subclasses to override — **illegal**. - `abstract` + `synchronized` → there's no body to synchronize — **illegal**. - `abstract` + `native` → both assert 'no Java body here' in different ways — **illegal** together. These are not arbitrary: each is the compiler rejecting a semantic contradiction. ## final: design intent and optimisation `final` on a method means **no subclass may override it**. Uses: - *Design*: freeze an algorithm (e.g. a template-method step you don't want altered), enforce invariants, prevent a subclass from breaking security-sensitive logic. - *Performance*: non-virtual binding enables inlining (though the modern JIT does much of this via class-hierarchy analysis anyway). - *Security*: a `final` method can't be overridden by a malicious subclass to subvert checks. ## synchronized: an implementation detail, not a contract `synchronized` on an instance method acquires that **instance's monitor** (`this`); on a `static` method it acquires the **Class object's monitor**. Important design points: - It is *not* part of the method signature or the interface — a subtype/override is free to drop it, so callers can't rely on it. *Effective Java*: prefer private lock objects / synchronized blocks over `synchronized` on a public method, because publishing the lock (the instance) lets outside code interfere. - Two `synchronized` instance methods on the same object are mutually exclusive; instance and static synchronized methods use *different* locks and don't exclude each other. ## access modifiers and overriding Access interacts with extensibility: - A `private` method is invisible to subclasses (no override; redeclaring it in a subclass is a new, unrelated method). - An override may only **widen** access (e.g. `protected` → `public`), never narrow it — narrowing would break substitutability. ## Putting it together: modifiers as contract The header's modifiers encode three orthogonal intents: 1. **Visibility** (access) — the API surface. 2. **Extensibility/dispatch** (`final`, `static`, `private`, `abstract`) — can this be specialised, and how is the actual implementation chosen? 3. **Concurrency/runtime** (`synchronized`, `native`, `strictfp`) — implementation concerns that ideally stay out of the published contract. The principal-level skill is reading a header and immediately knowing the override/dispatch story and which combinations are even legal, then using those modifiers deliberately to constrain how others may extend your type.
- Why is `abstract synchronized` illegal?synchronized describes how a method body acquires a lock, but an abstract method has no body to synchronize. The two assert opposite things (a defined locking behaviour vs no implementation), so the compiler rejects the combination.
- What lock does a synchronized static method use, and does it exclude a synchronized instance method?A synchronized static method locks the Class object's monitor; a synchronized instance method locks 'this'. They are different monitors, so they do not mutually exclude each other — a static-synchronized and an instance-synchronized method can run concurrently on the same class/instance.
saying these in an interview costs you the question
- Thinking static methods are overridden (they're hidden) or can be abstract
- Allowing abstract final / abstract static / abstract private as legal
- Believing synchronized is part of the method's overridable contract
- Claiming an override can narrow access
- Assuming instance-synchronized and static-synchronized methods share a lock