A method is overridden somewhere in a class hierarchy. How do you stop further subclasses from overriding it again, and what is the default if you do nothing?
answer
- override is implicitly open
- final override = seal the method here
- Stops fragile-base-class leaking deeper
- abstract override re-abstracts (opposite)
- Redundant in a final class
basics
~10 sBy default an overriding method stays open, so deeper subclasses can keep overriding it. To stop that, write final override on the method, which seals it.
solid answer
~40 sWhen you `override` an open member, your override is **implicitly open** — Kotlin keeps the extension point open down the chain so further subclasses can override it again. If you want to lock the behavior at a given level, declare it `final override`, which removes the openness while still satisfying the override. This is useful in a deep hierarchy where a mid-level class wants to guarantee its implementation is the final word (preventing the fragile-base-class problem from leaking deeper). Note the interaction with the class modifier: `final override` works only in a class that can still have subclasses (open/abstract); in a fully final class no further override is possible anyway. You can also re-open or keep open by simply writing `override` (default). The keywords in play are `override`, `open`, and `final`.
code
kotlin · 3 linesopen class A { open fun f() = "A" }
open class B : A() { final override fun f() = "B" }
// open class C : B() { override fun f() = "C" } // ERROR: f is final in Bgo deeper
May not know overrides stay open; can at least state final forbids overriding.
Knows overrides are implicitly open and that final override seals a single member.
Applies final override deliberately to bound an extension point and explains the fragile-base-class motivation.
Designs layered hierarchies choosing per-method open/final/abstract to encode invariants and minimize the inheritance contract.
## The implicit-open rule for overrides Kotlin treats an `override` as **implicitly `open`**. So in a chain A → B → C, if A declares `open fun f()` and B does `override fun f()`, then C can still `override fun f()` — B's override did not close it. ```kotlin open class A { open fun f() = "A" } open class B : A() { override fun f() = "B" } // still open open class C : B() { override fun f() = "C" } // allowed ``` ## Sealing with `final override` To make B's implementation the last word, prefix `final`: ```kotlin open class B : A() { final override fun f() = "B" } // sealed here // class C : B() { override fun f() = "C" } // ERROR: f is final in B ``` `final override` says "I am overriding the parent's open member, and I forbid anyone below me from overriding it again." It is the precise tool for controlling how far an extension point propagates. ## Why this matters (design) Leaving every override open enlarges the *inheritance contract*: each level must remain correct under arbitrary re-override. Sealing with `final override` at the layer that owns the invariant shrinks that surface — a deliberate defense against the fragile base class problem, where deep subclasses break when they re-override and bypass invariants. ## Interaction with class openness - In a **final class**, no subclass exists, so `final override` is redundant (members are unoverridable anyway). - In an **open/abstract class**, `final override` is meaningful: subclasses exist but cannot touch that member. - An **abstract override** (`abstract override fun f()`) re-abstracts a member, forcing concrete subclasses to re-implement — the opposite of sealing. ## Summary of modifiers on an override | You write | Effect on deeper subclasses | |---|---| | `override fun f()` | still open (can re-override) | | `final override fun f()` | sealed (cannot re-override) | | `abstract override fun f()` | must re-implement |
- What does `abstract override fun f()` do?It re-declares an inherited member as abstract, forcing every concrete subclass below to provide its own implementation again.
- Is `final override` ever needed in a final class?No. A final class has no subclasses, so its members cannot be overridden regardless; the `final` is redundant there.
saying these in an interview costs you the question
- Believing an override is final by default
- Not knowing `final override` exists
- Confusing `final override` with `abstract override`
- Thinking the class's final modifier is needed to seal one method