skip to content

Inheritance & Interfaces

How Kotlin handles subtyping: everything is final until you open it, overrides are explicit, and interfaces can carry default implementations. The defaults here encode a design opinion that interviewers like to discuss.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

explore

questions

25

What is an abstract class in Kotlin, and how do you declare an abstract member that subclasses must implement?

level: juniorimportance: must knowfreq 80%

answer

  1. abstract = cannot instantiate
  2. abstract member = no body, must override
  3. concrete subclass overrides all or stays abstract
  4. can hold state + constructors unlike interfaces
  5. object : Abstract() {} fills it in

basics

~10 s

An abstract class is one you cannot create objects from directly. It can have members marked abstract that have no body, and any non-abstract subclass must provide their implementation.

solid answer

~30 s

An abstract class is declared with the abstract keyword and cannot be instantiated directly; you must subclass it. Inside it you can declare abstract members (functions or properties) using the abstract keyword with no body or initializer, e.g. abstract fun area(): Double. A non-abstract (concrete) subclass must override every inherited abstract member with the override keyword, or it must itself be declared abstract. Abstract classes can also contain normal concrete methods, state (backing fields), constructors, and init blocks. Trying to write val s = Shape() where Shape is abstract is a compile error.

code

kotlin · 11 lines
kotlin
abstract class Shape {
    abstract fun area(): Double
    fun printArea() = println(area())
}

class Square(val side: Double) : Shape() {
    override fun area() = side * side
}

// val s = Shape()  // ERROR: cannot create instance of abstract class
Square(2.0).printArea()  // 4.0

go deeper

for a junior

Knows abstract classes can't be instantiated and abstract members must be overridden by concrete subclasses.

for a middle

Explains mixing concrete and abstract members, constructors, and the exact compiler errors for missing overrides or instantiation.

for a senior

Contrasts abstract classes vs interfaces (state, constructors, single inheritance) and knows anonymous-object instantiation.

for a principal

Frames abstract classes as a design tool for shared invariant state and template behavior, weighing them against interfaces and composition.

## What 'abstract' means An **abstract class** is a class that is incomplete: it declares behavior but leaves some of it unimplemented, so it cannot be turned into an object by itself. You mark it with the `abstract` keyword. ```kotlin abstract class Shape { abstract val name: String // abstract property: no initializer abstract fun area(): Double // abstract function: no body fun describe(): String = // concrete method, fully implemented "$name has area $area" } ``` ## Abstract members A member marked `abstract` has **no implementation**: an abstract function has no `{ }` body, and an abstract property has no initializer and no getter body. It is a contract that says "every concrete subclass must supply this." ## Concrete subclasses must override A non-abstract subclass MUST provide a body for every inherited abstract member using `override`: ```kotlin class Circle(val r: Double) : Shape() { override val name = "circle" override fun area() = Math.PI * r * r } ``` If a subclass forgets one, the compiler reports "Class 'Circle' is not abstract and does not implement abstract member." A subclass may instead stay `abstract` and leave the member unimplemented for the next level down. ## Cannot instantiate `Shape()` is a compile error: "Cannot create an instance of an abstract class." You can only instantiate concrete subclasses, or use an `object : Shape() { ... }` anonymous object that fills in the abstract members. ## Mixing concrete and abstract Abstract classes are not all-or-nothing: they can hold normal methods, mutable/immutable state with backing fields, constructors, and `init` blocks — unlike interfaces, which have no constructor and no backing-field state.

  • Can an abstract class have a constructor?
    Yes. It can declare primary and secondary constructors with parameters and init blocks; subclasses call them via the super-constructor call in their supertype list, e.g. `: Shape(x)`.
  • Must every member of an abstract class be abstract?
    No. It can freely mix abstract members with fully implemented concrete methods, properties, and state.

An abstract class is like a blank form with some fields pre-filled and others left empty — you can't 'use' the blank form itself, only a completed copy.

saying these in an interview costs you the question

  • Saying you can instantiate an abstract class directly
  • Claiming all members of an abstract class must be abstract
  • Forgetting the override keyword when implementing an abstract member
  • Thinking an abstract class cannot hold state or a constructor
  • Confusing abstract with private — abstract is about missing implementation, not visibility

context

open as a page

A class implements two interfaces that both provide a default implementation of the same method foo(). What does Kotlin require you to do, and why won't it compile otherwise?

level: juniorimportance: must knowfreq 55%

basics

~10 s

Both interfaces give a body for the same method, so Kotlin can't pick one for you. You must override the method in your class. Otherwise the compiler reports an error and refuses to build.

open as a page

In Kotlin, can an interface provide a default implementation for a method? Show how and explain what a class gets when it implements that interface.

level: juniorimportance: must knowfreq 70%

basics

~10 s

Yes. A Kotlin interface method can include a body. Classes that implement the interface inherit that body for free and only need to override it if they want different behavior.

open as a page

In Kotlin, are classes open for subclassing by default? What do you write to allow a class to be subclassed?

level: juniorimportance: must knowfreq 85%

basics

~10 s

No. By default Kotlin classes are final, so you cannot extend them. To allow subclassing you mark the class with the open keyword.

open as a page

In Kotlin, why is the `override` keyword mandatory when redefining a member from a superclass or interface, and what happens if you omit it?

level: juniorimportance: must knowfreq 75%

basics

~10 s

You must write override before a function or property that replaces one from the parent. It makes your intent explicit. If you forget it, the code does not compile.

open as a page

Kotlin classes and members are final by default. How does the abstract modifier interact with this rule, and why don't you need to write 'open' on an abstract member?

level: middleimportance: must knowfreq 70%

basics

~10 s

In Kotlin everything is closed for inheritance unless you open it. Marking something abstract automatically makes it open, because an abstract member with no body only makes sense if subclasses can override it.

open as a page

Inside an overriding method, how do you call a specific parent's implementation when several supertypes are involved? Show the exact syntax and explain how the target is chosen.

level: middleimportance: must knowfreq 50%

basics

~10 s

Use super<TypeName>.method(). The name in angle brackets is the exact parent whose version you want to run. You can call several parents this way, in any order, from inside your override.

open as a page

How do properties work in Kotlin interfaces? Explain abstract properties (no backing field) and properties with default accessors.

level: middleimportance: must knowfreq 60%

basics

~10 s

An interface property has no stored value—no backing field. It can be abstract (the class must provide it) or it can define a getter that computes a value from other members.

open as a page

Inside an `open class`, is a regular method automatically overridable? Explain how `open` applies to members versus the class itself.

level: middleimportance: must knowfreq 70%

basics

~10 s

No. Marking the class open only allows subclassing. Each method or property is still final and must be marked open separately to be overridable.

open as a page

How do you call the parent implementation of a function from inside an override using `super`, and when is doing so useful?

level: middleimportance: must knowfreq 70%

basics

~10 s

Inside an overriding function, write super.functionName(args) to run the parent's version. It is useful when you want to extend the parent behavior rather than fully replace it.

open as a page

When does the diamond actually force an override, and when does it NOT? Walk through the cases of abstract vs. default members across the supertypes.

level: middleimportance: should knowfreq 38%

basics

~20 s

You're forced to override only when more than one parent supplies a body for the same method. If only one parent has a body (or none do for an abstract member you must implement anyway), there's no conflict to resolve.

open as a page

Kotlin allows a class to implement multiple interfaces but extend only one class. How do interfaces act as multiple-supertype contracts, and what does the type see?

level: middleimportance: should knowfreq 50%

basics

~20 s

A class can list several interfaces after the colon, separated by commas, and must satisfy all of them. It then counts as each of those types, so it can be passed wherever any one of them is expected.

open as a page

How do you override a property in Kotlin, and what rules govern overriding a `val` with a `var` or changing its accessor?

level: middleimportance: should knowfreq 55%

basics

~10 s

Mark the parent property open, then redeclare it with override val/override var. You may override a val with a var (adding a setter), but not a var with a val.

open as a page

Can an abstract class declare a member abstract when its superclass already provides a concrete (non-abstract) implementation of that member? When is this useful?

level: seniorimportance: should knowfreq 35%

basics

~10 s

Yes. An abstract subclass can override an inherited open method and re-declare it as abstract, removing the inherited implementation and forcing its own subclasses to supply a new one.

open as a page

When designing a type hierarchy, when would you choose an abstract class over an interface in Kotlin, given interfaces can have default method implementations?

level: seniorimportance: should knowfreq 55%

basics

~10 s

Choose an abstract class when you need shared stored state, a constructor, or want to allow only one parent. Choose an interface when you want a contract many unrelated types can implement and combine.

open as a page

Two interfaces both provide a default getter for the same property. How does diamond resolution apply to properties, and what limitation around interface state should you keep in mind?

level: seniorimportance: should knowfreq 25%

basics

~20 s

The same rule applies: if two interfaces give a body (a getter) for the same property, you must override it and can pick a parent's getter with super<Type>.prop. Interfaces can't hold real fields, so there's no stored state to clash — only the accessor logic.

open as a page

Now that Kotlin interfaces can have default method bodies and property accessors, when would you still choose an abstract class over an interface?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Use 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.

open as a page

Final-by-default breaks Spring proxies and Mockito by default. How does the Kotlin ecosystem reconcile final-by-default with frameworks that need to subclass your classes?

level: seniorimportance: should knowfreq 40%

basics

~10 s

Many frameworks create runtime subclasses (proxies/mocks), which final classes block. Kotlin provides compiler plugins like all-open (and kotlin-spring) that automatically open annotated classes so those tools work.

open as a page

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?

level: seniorimportance: should knowfreq 45%

basics

~10 s

By 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.

open as a page

An overriding member in Kotlin is itself implicitly `open`. What does that mean for deeper subclasses, and how do you stop further overriding with `final override`?

level: seniorimportance: should knowfreq 45%

basics

~10 s

When you override something, that override can also be overridden by classes below you — it stays open automatically. Write final override to seal it so no further subclass can change it.

open as a page

What is the design rationale for making Kotlin classes final by default, and what are the trade-offs versus Java's open-by-default model?

level: principalimportance: should knowfreq 30%

basics

~10 s

Final-by-default protects against accidental inheritance and the fragile base class problem, pushing teams toward composition and interfaces. The trade-off is more friction when frameworks or extension genuinely need subclassing.

open as a page

What are the limits on what an interface default method or accessor can do regarding state, and how do teams work around the lack of interface fields?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

Default methods can't store or remember anything because interfaces have no fields. They can only use parameters and call other interface members. To keep state, implementers add their own property, which the interface declares as an abstract property.

open as a page

What is the danger of calling an open or abstract member from the constructor (or init block / property initializer) of an abstract base class, and what does Kotlin do at that point?

level: principalimportance: nice to knowfreq 25%

basics

~20 s

When a base class is being constructed, the subclass part isn't set up yet. If the base constructor calls a method the subclass overrides, that override runs before the subclass's fields exist, so it may see uninitialized values or null.

open as a page

How does Kotlin's diamond resolution interoperate with Java default methods, and when would you reach for super<Type>.foo() in real design (e.g. mixin/trait-style composition) versus restructuring the hierarchy?

level: principalimportance: nice to knowfreq 15%

basics

~20 s

Java default methods behave like Kotlin interface defaults, so the same 'override and qualify' rule applies when a Kotlin class mixes them. In design, use super<Type>.foo() to deliberately combine small reusable behaviors; if conflicts pile up, it's a sign to rethink the hierarchy.

open as a page

What is covariant return-type overriding in Kotlin, and what subtle correctness pitfalls arise when an open member is called during a superclass constructor while a subclass override depends on uninitialized state?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

An override may return a more specific subtype than the parent (covariant return). Danger: if a parent constructor calls an open method, the subclass override runs before the subclass's own fields are set, so it may see null/zero values.

open as a page