Chapter 13: Interfaces
Interfaces — this is one of the most powerful and most used features in Kotlin!
In Kotlin, interfaces are much more expressive than in Java — especially since Kotlin 1.0 and with the improvements in later versions. You’ll love how clean, flexible, and safe they are.
We’re going to go super slowly, like we’re sitting together in a quiet Mumbai café — I’ll explain every single concept with real-life analogies, complete runnable programs, step-by-step breakdowns, tables, common mistakes with fixes, and tons of examples you can copy-paste and run right now.
Let’s dive in! ☕🚀
1. Interface Declaration & Implementation
Interface in Kotlin is a contract — it defines what a class must do, but not how.
Syntax (very clean):
|
0 1 2 3 4 5 6 7 8 |
interface Flyable { fun fly() // Abstract method – no body } |
Implementing an interface (using 🙂
|
0 1 2 3 4 5 6 7 8 9 10 |
class Bird : Flyable { override fun fly() { println("Bird is flying with wings! 🐦") } } |
Key points:
- No implements keyword — just : (same as inheritance)
- All methods in interface are abstract by default — no need to write abstract
- All properties in interface are abstract too (no backing field)
Example – Multiple methods
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
interface Vehicle { fun startEngine() fun stopEngine() val speedLimit: Int // Abstract property } class Car : Vehicle { override val speedLimit = 120 override fun startEngine() { println("Car engine started! Vroom vroom!") } override fun stopEngine() { println("Car engine stopped.") } } fun main() { val myCar = Car() myCar.startEngine() println("Max speed: ${myCar.speedLimit} km/h") } |
2. Default Implementations in Interfaces
Since Kotlin 1.0 (and improved in later versions), interfaces can have default method implementations — just like Java 8+.
This is huge — you can evolve interfaces without breaking existing code!
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
interface Logger { fun log(message: String) { println("[LOG] $message") // Default implementation } fun logError(message: String) { println("[ERROR] $message") } } class ConsoleLogger : Logger { // No need to implement log() – uses default } fun main() { val logger = ConsoleLogger() logger.log("App started successfully!") logger.logError("Failed to connect to database") } |
Overriding default implementation (optional)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
class FileLogger : Logger { override fun log(message: String) { println("[FILE] Writing to log: $message") // You can still call default if needed: // super.log(message) } } |
3. Functional Interfaces (fun interface)
A functional interface is an interface with exactly one abstract method — perfect target for lambdas!
Kotlin gives you a special marker: fun interface
|
0 1 2 3 4 5 6 7 8 |
fun interface Greeter { fun greet(name: String) } |
Using it with lambda
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
fun main() { val helloGreeter: Greeter = Greeter { name -> println("नमस्ते $name! 😊") } helloGreeter.greet("Webliance") } |
Why use fun interface?
- Makes it explicit that this interface is meant for lambdas
- Allows SAM conversion (Single Abstract Method) — lambda becomes instance automatically
- Very common in Android (listeners), callbacks, etc.
Example – Real-world Android-style listener
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
fun interface OnClickListener { fun onClick() } class Button { var onClickListener: OnClickListener? = null fun click() { onClickListener?.onClick() } } fun main() { val button = Button() button.onClickListener = OnClickListener { println("Button clicked! 🎉") } button.click() } |
4. Multiple Inheritance with Interfaces
Kotlin fully supports multiple inheritance through interfaces (but not classes — only one parent class).
A class can implement any number of interfaces.
Example – Multiple inheritance
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
interface Flyable { fun fly() = println("Flying high!") } interface Swimmable { fun swim() = println("Swimming gracefully!") } class Duck : Flyable, Swimmable { override fun fly() { super<Flyable>.fly() // Call specific super println("Duck is flying low!") } } fun main() { val donald = Duck() donald.fly() // Calls overridden + default donald.swim() // Uses default implementation } |
Output:
|
0 1 2 3 4 5 6 7 8 |
Flying high! Duck is flying low! Swimming gracefully! |
Resolving conflicts (if two interfaces have same method):
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
interface A { fun hello() = println("Hello from A") } interface B { fun hello() = println("Hello from B") } class C : A, B { override fun hello() { super<A>.hello() // Call A's version super<B>.hello() // Call B's version println("Hello from C") } } |
Quick Recap Table (Your Cheat Sheet)
| Feature | Kotlin Way (Best Practice) | Key Point |
|---|---|---|
| Interface declaration | interface Flyable { fun fly() } | No abstract needed |
| Default implementation | fun log() { println(“…”) } | Safe to add without breaking code |
| fun interface | fun interface OnClick { fun onClick() } | Perfect for lambdas |
| Multiple inheritance | class Duck : Flyable, Swimmable | Allowed with interfaces |
| Call specific super | super<Flyable>.fly() | Resolves conflicts |
Common Newbie Mistakes & Fixes
| Mistake | Problem | Fix |
|---|---|---|
| Forgetting override when implementing | Compile error | Always write override for abstract methods |
| Not marking interface method as open | Cannot override | No need — all interface methods are open |
| Using class instead of interface | Cannot implement multiple | Use interface for contracts |
| Forgetting fun interface for lambdas | Lambda conversion not allowed | Add fun interface |
| Not handling conflicts in multiple inheritance | Compile error | Override and use super<Interface>.method() |
Homework for You (Let’s Make It Fun!)
- Basic Create interface Printable with method printDetails(). Implement it in Book and Movie classes.
- Medium Create interface Logger with default logInfo() and logError(). Implement it in ConsoleLogger that overrides logError().
- Advanced Create two interfaces Eatable and Flyable. Make Bat implement both → override fly() to call both defaults.
- Fun Create fun interface OnLoginListener → use lambda to handle login success/failure.
- Challenge Create interface Resizable with default resize(factor: Double) → implement in Circle and Rectangle.
You’ve just mastered Kotlin’s powerful interface system — now you can design clean, flexible, and reusable contracts!
