liveBook · Manning

Override

As explained in Kotlin in Action, 2E

Method overriding is the definition of a subclass member function that replaces an inherited implementation with the same signature.

In Kotlin, override marks a member function or property that supplies a subclass or interface implementation in place of an inherited one. The modifier is mandatory: unlike Java’s optional @Override annotation, Kotlin requires an explicit declaration of that intent. This makes an accidental override—or a missing override after an API changes—a compile-time error. section 4.1.1 section 4.1.2

Listing 3.6 Overriding a member function
open class View {                                      #1
    open fun click() = println("View clicked")         #2
}
 
class Button: View() {                                 #3
    override fun click() = println("Button clicked")   #4
}

A base class must opt in to inheritance with open, and each member intended for replacement must also be open. Button then replaces View.click with its own implementation. section 3.3.4 section 4.1.2

Calls to overridden member functions use the runtime type of the object. A variable declared as View can hold a Button, and calling click invokes Button’s implementation. Kotlin is deliberately conservative about enabling this: classes and members are final by default, so inheritance and overriding must be designed explicitly. This helps avoid fragile base-class behavior when subclasses depend on assumptions that later base-class changes invalidate. section 3.3.4 section 4.1.2

Override behavior is controlled by a few related rules:

  • Implementing an abstract interface member requires an override. An interface may also provide a default method body; a class can inherit it or redefine it. section 4.1.1
  • When two interfaces provide the same default method, neither implementation wins. Provide an override explicitly, and select inherited implementations with super<Interface>.method(). section 4.1.1
  • An overridden member is open to further overriding by default. Mark it final override when subclasses must not replace that implementation. section 4.1.2
  • Properties can also implement interface properties with override, whether the value comes from a constructor property, a custom getter, or initialization. section 4.2.3

Resolving competing interface defaults

A Button that implements both Clickable and Focusable must override showOff when both interfaces define it. Its override can call each selected default implementation: class Button : Clickable, Focusable { override fun click() = println("I was clicked") override fun showOff() { super<Clickable>.showOff() super<Focusable>.showOff() } } The explicit implementation makes the combined behavior unambiguous. section 4.1.1

Do not confuse member overriding with extension functions. Extensions are declared outside a class and are resolved from the variable’s declared static type, even when its runtime value is a subtype. A member with the same signature takes precedence over an extension, and an extension cannot override that member. This matches extensions’ compilation as static Java functions with the receiver passed as an argument. section 3.3.4 section 9.2.1

Common overrides refine universal object behavior. Overriding toString produces useful logging or debugging output. Overriding equals defines value equality, which Kotlin uses for ==; a matching hashCode implementation is needed when instances are used in hash-based collections. Because equals comes from Any, it is an override rather than an extension. section 4.3.1 section 9.2.1

How Kotlin in Action, 2E covers it

How deep it goes
Explains open and final eligibility, runtime dispatch, interface conflicts, property implementations, and extension-function limits.
Examples
Uses View and Button clicks, competing Clickable and Focusable defaults, user nickname properties, Customer equality, and Point equality.
What it assumes
Assumes familiarity with classes and member functions while introducing Kotlin inheritance and interface override syntax directly.
What you can do after
Apply it to implement interface contracts, specialize explicitly open members, resolve default-method conflicts, and customize object behavior.
How it connects
Connects inheritance, interfaces, open, final, abstract, extension functions, properties, equals, hashCode, and toString.

Also explained in

Compare how 3 books explain override →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.