Interfaces & Abstract Classes
Reviewed & published by Brayan K
An interface is a contract of capabilities a type can declare and optionally implement, while an abstract class is a partially-implemented base that can also hold state and a constructor.
Part of the free Kotlin course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
You'll learn abstract and default methods, properties in interfaces, implementing multiple interfaces, when to choose an abstract class, and resolving conflicts with super<Type>.
What You'll Learn in This Lesson
- Declaring abstract and default methods in an interface
- Abstract and computed properties in interfaces
- Implementing an interface with override
- Implementing multiple interfaces at once
- Resolving conflicts with super<Type>
- When to use an abstract class instead
1️⃣ Interfaces: Abstract + Default Members
An interface declares what a type can do. A method with no body is abstract — every implementer must provide it. A method with a body is a default implementation that implementers inherit for free. Interfaces can also declare properties, though those must be abstract or computed (no stored value).
// An interface declares WHAT a type can do. Methods can be abstract
// (no body) or have a DEFAULT implementation that classes inherit.
interface Greeter {
val name: String // abstract property — implementers must provide it
fun greet(): String // abstract method — implementers must write it
fun greetLoudly(): String { // default method — implementers may reuse it
return greet().uppercase()
}
}
class FriendlyGreeter(override val name: String) : Greeter {
override fun greet(): String = "Hi, I'm $name"
}
fun main() {
val g = FriendlyGreeter("Ada")
println(g.greet()) // -> Hi, I'm Ada
println(g.greetLoudly()) // -> HI, I'M ADA
}The override keyword is required when implementing an interface member, and the default greetLoudly() reuses the abstract greet() without the class writing it again.
2️⃣ Implementing Multiple Interfaces
A class can implement several interfaces at once — that's how Kotlin composes independent behaviours despite allowing only one superclass. If two interfaces provide a default method with the same signature, the compiler forces you to override it and pick which implementation to use via super<Interface>.
// A class can implement MANY interfaces (unlike single inheritance).
interface Swimmer {
fun move(): String = "swimming"
}
interface Flyer {
fun move(): String = "flying"
}
// When two interfaces give the SAME default method, you MUST override it
// and pick which one(s) to use with super<Interface>.
class Duck : Swimmer, Flyer {
override fun move(): String {
return super<Swimmer>.move() + " and " + super<Flyer>.move()
}
}
fun main() {
val duck = Duck()
println(duck.move()) // -> swimming and flying
}Inside the override you can call one, the other, or both qualified supers — here Duck.move() combines them.
3️⃣ Abstract Classes: State + Constructor
An abstract class goes further than an interface: it can store real properties, run a constructor, and keep internal state, while still leaving some members abstract for subclasses to implement. Use one when subclasses share state or setup logic; use an interface when you only need to declare capabilities or mix several together.
// An ABSTRACT class can hold state and a constructor, and mixes
// abstract members (subclasses must implement) with concrete ones.
abstract class Shape(val name: String) {
abstract fun area(): Double // no body — subclasses provide it
fun describe(): String { // concrete — shared by all shapes
return "$name has area ${area()}"
}
}
class Rectangle(val w: Double, val h: Double) : Shape("Rectangle") {
override fun area(): Double = w * h
}
fun main() {
val r = Rectangle(3.0, 4.0)
println(r.area()) // -> 12.0
println(r.describe()) // -> Rectangle has area 12.0
}Shape holds a name and provides a concrete describe(), while each subclass supplies its own area() — something a pure interface couldn't do with stored state.
Your turn. Fill in the ___, then run and compare.
// 🎯 YOUR TURN — replace the ___ then run main()
interface Clickable {
fun click(): String
fun describe(): String = "A clickable thing" // default method
}
// Implement the interface. Use the right keyword on the method.
class Button : Clickable {
___ fun click(): String = "clicked!" // 👉 put "override" in the blank
}
fun main() {
val b = Button()
println(b.click()) // ✅ Expected: clicked!
println(b.describe()) // ✅ Expected: A clickable thing
}Mini-Challenge: Shapes with an Interface
Define an interface with one abstract method and one default method, then implement it.
// 🎯 MINI-CHALLENGE: shapes with an interface.
// Save as Shapes.kt and run main().
//
// 1. Define an interface Shape with an abstract fun area(): Double
// and a DEFAULT fun label(): String that returns "area = " + area().
// 2. Make a class Square(val side: Double) that implements Shape,
// where area() returns side * side.
// 3. Create Square(5.0) and print area() then label().
//
// ✅ Expected output:
// 25.0
// area = 25.0
fun main() {
// your code here
}Common Errors (and the fix)
- ❌ "'greet' overrides nothing" or "must override" — You forgot the override keyword on an implemented member. ✅ Add override before fun.
- ❌ "Class must be declared abstract or implement member" — You left an abstract method unimplemented. ✅ Provide a body for every abstract member, or mark the class abstract.
- ❌ "Many supertypes available, please specify" — Two interfaces share a default method. ✅ Override it and call super<Interface>.method().
- ❌ Property with a value in an interface — Interfaces can't store fields. ✅ Make the property abstract, or give it a custom get().
Pro Tips
- 💡 Prefer interfaces by default: they compose freely; switch to an abstract class only when you need stored state or a constructor.
- 💡 Default methods reduce duplication: build shared behaviour on top of a few abstract members.
- 💡 Computed properties work in interfaces: val ready: Boolean get() = ... needs no backing field.
📋 Quick Reference — Interfaces & Abstract Classes
| Concept | Kotlin Syntax |
|---|---|
| Declare interface | interface Greeter { ... } |
| Default method | fun greetLoudly(): String { ... } |
| Implement it | class C : Greeter { ... } |
| Multiple interfaces | class Duck : Swimmer, Flyer |
| Disambiguate | super<Swimmer>.move() |
| Abstract class | abstract class Shape(...) |
🎉 Lesson Complete!
- ✅ Interfaces declare capabilities with abstract and default members
- ✅ Interface properties must be abstract or computed
- ✅ A class can implement many interfaces but extend one class
- ✅ super<Type> resolves clashing default methods
- ✅ Abstract classes add stored state and a constructor
Practice quiz
An interface method with no body is…
- abstract — implementers must provide it
- a default method
- a private method
- automatically static
Answer: abstract — implementers must provide it. A method without a body is abstract; every implementer must supply it.
What is a default method in an interface?
- A method that returns null
- A method with a body that implementers inherit for free
- A method that cannot be overridden
- The first method declared
Answer: A method with a body that implementers inherit for free. A default method provides a body that implementers inherit unless they override it.
What restriction applies to properties declared in an interface?
- They must be private
- They must be var
- They cannot store a value in a backing field
- They must be nullable
Answer: They cannot store a value in a backing field. Interface properties must be abstract or computed — no backing field/stored value.
Which keyword is required when implementing an interface member?
- open
- implement
- super
- override
Answer: override. Implementing an interface member requires the override keyword.
How many interfaces can a single class implement?
- As many as needed
- Exactly one
- At most two
- None
Answer: As many as needed. A class can implement many interfaces, though it extends only one class.
If two interfaces supply the same default method, what must the class do?
- Ignore both
- Override it and disambiguate the super call
- Delete one interface
- Nothing — Kotlin picks one
Answer: Override it and disambiguate the super call. The class must override the method and pick which default via super<Interface>.
What does super<Swimmer>.move() do?
- Creates a new Swimmer
- Calls the Swimmer interface's default move()
- Makes move() abstract
- Returns null
Answer: Calls the Swimmer interface's default move(). It calls the move() default implementation specifically from the Swimmer interface.
What can an abstract class do that an interface cannot?
- Declare abstract methods
- Provide default method bodies
- Be a supertype
- Hold stored state and have a constructor
Answer: Hold stored state and have a constructor. Abstract classes can store real properties and run a constructor; interfaces cannot.
When should you prefer an interface over an abstract class?
- When you need shared stored state
- When you want to mix several independent capabilities
- When you need a constructor
- When you need a backing field
Answer: When you want to mix several independent capabilities. Interfaces compose freely, so prefer them for mixing multiple capabilities.
Which is a valid interface property?
- val count: Int = 5
- val ready: Boolean get() = true
- private var x = 0
- lateinit var s: String
Answer: val ready: Boolean get() = true. A computed property with a getter is allowed; a stored value with a backing field is not.
Continue this course
- Previous: Sequences (Lazy Collections)
- Next: Object Expressions & Declarations — Singletons with object, and anonymous objects for inline implementations
- Quick reference: Kotlin cheat sheet
Frequently asked questions
What is the difference between an interface and an abstract class?
An interface describes a set of capabilities and can declare abstract methods, default method bodies, and abstract properties — but it cannot hold state with a backing field or have a constructor. An abstract class can do all that plus store real properties, run constructor logic, and keep internal state. The biggest practical difference is that a class may implement many interfaces but inherit from only one class, so reach for interfaces when you want to mix in several behaviours, and an abstract class when you need shared state or a common constructor.
Can an interface have a default method body?
Yes. A method in a Kotlin interface can provide a default implementation that all implementers inherit unless they override it. This lets you offer ready-made behaviour built on top of the abstract members — for example greetLoudly() calling the abstract greet(). Interfaces can also declare properties, but those properties cannot store a value directly (no backing field); they must be abstract or computed from a getter.
Why would a class implement more than one interface?
Kotlin allows only single class inheritance, but a type often needs several independent capabilities — something might be both Clickable and Draggable, or both Swimmer and Flyer. Implementing multiple interfaces composes those behaviours without forcing an artificial class hierarchy. If two interfaces happen to supply the same default method, the compiler makes you override it and disambiguate which one you want using super<InterfaceName>.
What does super<Interface> do?
When a class inherits the same-named method from two interfaces, calling super.method() is ambiguous. The qualified syntax super<Swimmer>.move() tells the compiler exactly which interface's default implementation you mean. You can call one, the other, or both inside your override — which is how the Duck example combines swimming and flying into a single move() result.