Now that Kotlin interfaces can have default method bodies and property accessors, when would you still choose an abstract class over an interface?
answer
- Interface = no state, no constructor, no `init`
- Abstract class = backing fields + constructor + `init`
- Many interfaces vs one superclass
- Abstract class can mark members `final`/`protected`
- No state? Prefer interface for composability
basics
~20 sUse an interface when you only need behavior contracts and want a type to implement several. Use an abstract class when you need stored state, a constructor, or initialization logic, since interfaces can't hold any of those.
solid answer
~50 sBoth can carry concrete behavior now, so the deciding factor is **state and identity**. Abstract classes can have backing fields (stored state), constructors with parameters and `init` blocks, and ordered initialization—interfaces have none of that. A class can implement many interfaces but extend only one class, so interfaces win when you need multiple-supertype composition. Interfaces let you declare property *contracts* and computed accessors but cannot store a value; abstract classes can declare `protected` stored state and template-method scaffolding around it. Choose an abstract class when implementers must share real state or a constrained construction path; choose an interface for pure capability/behavior contracts, mixins, and when a single class must satisfy several of them. Visibility also differs: interface members are public/open and can't be `final` or hold non-public state, while abstract classes support `protected`, `final` overrides, and private helpers with fields.
code
kotlin · 19 lines// State + init + final template method => abstract class
abstract class Game {
private var started = false
fun play() { // final by default in classes
check(!started); started = true
setup(); loop()
}
protected abstract fun setup()
protected abstract fun loop()
}
// Pure capabilities, composable => interfaces
interface Pausable { fun pause() }
interface Savable { fun save() = println("saved") }
class Chess : Game(), Pausable, Savable {
override fun setup() {}
override fun loop() {}
override fun pause() {}
}go deeper
Knows interfaces are for contracts and classes can hold data, but may not articulate the precise state/constructor distinction.
Lists that interfaces lack state/constructor and that you can implement many interfaces but extend one class.
Gives a clear decision framework around state, init, final members, visibility, and composition, with examples.
Weighs API evolution, binary compatibility, and team conventions when choosing interface vs abstract class for a long-lived public API.
## They now overlap on behavior Since Kotlin interfaces support **default method bodies** and **property accessors (`get()`)**, the old "interface = no code" rule is gone. So the choice hinges on what *only one of them* can do. ## What only an abstract class can do - **Stored state / backing fields.** An abstract class can hold real fields: `protected var state = 0`. Interfaces have no backing field, so they cannot store anything. - **Constructors and `init`.** Abstract classes have constructors (with parameters), `init` blocks, and a defined initialization order. Interfaces have no constructor, so they cannot run construction-time logic or take parameters. - **Non-public members with state.** Abstract classes support `protected`/`private` members and private fields for internal scaffolding. Interface members are `public` and `open`; you can't make them `final` or back them with hidden state. - **`final` members.** An abstract class can mark a method `final` to forbid overriding (template-method pattern). Interface members are always open. ## What only an interface can do - **Multiple-supertype composition.** A class can implement many interfaces but extend only one class. Interfaces are the tool for mixins/capability composition. - **Lightweight contracts** with optional computed defaults, no constructor obligations. ## Decision guide ```kotlin // Need shared mutable/initialized state + single hierarchy -> abstract class abstract class Repository(private val conn: Connection) { // ctor + state init { conn.open() } // init logic protected val cache = mutableMapOf<String, Any>() // backing field abstract fun load(id: String): Any fun cached(id: String) = cache.getOrPut(id) { load(id) } // could be final } // Need composable capability contracts -> interface(s) interface Cacheable { val key: String } interface Timestamped { val createdAt: Long; fun age(now: Long) = now - createdAt } class Doc(override val key: String, override val createdAt: Long) : Cacheable, Timestamped ``` ## Rule of thumb - Pick an **abstract class** when implementers must **share real state, a constructor, or initialization**, or you want to lock down some methods as `final`. - Pick an **interface** when you're defining **pure behavior/capability contracts**, especially if a type should satisfy **several** of them. - When in doubt and there's no state, prefer the interface — it's more composable and avoids burning the single allowed superclass slot.
- If neither state nor a constructor is needed, which is the default choice and why?Prefer an interface: it is more composable (a type can implement several), it doesn't consume the single allowed superclass slot, and default methods still let you ship behavior.
- Can you forbid overriding a method in an interface?No. Interface members are always open; to make a method `final` you need an (abstract) class.
An interface is a job description (capabilities required); an abstract class is a partially-built machine with internal parts already wired in that you finish assembling.
saying these in an interview costs you the question
- Saying interfaces can now hold state, so abstract classes are obsolete
- Forgetting that interfaces have no constructor/init
- Not mentioning multiple-supertype composition as the interface advantage
- Claiming you can mark interface members `final`