Question
Kotlin Inheritance and Interface Implementation: Extend a Class and Implement an Interface
Question
In Java, a class can extend a superclass while implementing one or more interfaces:
class MyClass extends SuperClass implements MyInterface {
// ...
}
Can Kotlin do the equivalent? Assume that SuperClass is abstract and does not implement MyInterface.
Short Answer
Kotlin supports extending one class and implementing one or more interfaces. Instead of separate extends and implements keywords, Kotlin uses a single colon (:) followed by the superclass and interfaces. By the end, you will know the syntax, how constructors affect inheritance, and how to implement required interface members.
Concept
Kotlin supports single inheritance for classes: a class can have one direct superclass. It also supports implementing multiple interfaces.
Kotlin combines Java's extends and implements syntax into one list after a colon:
class Child : Parent(), SomeInterface, AnotherInterface
Parent()meansChildinherits fromParentand calls its constructor.SomeInterfaceandAnotherInterfaceare interfaces thatChildimplements.- If the parent class constructor needs arguments, provide them inside the parentheses.
An abstract superclass does not need to implement the interface itself. The subclass can inherit from that abstract superclass and independently implement the interface.
This matters because many designs use an abstract base class for shared state or shared behavior, then use interfaces to express capabilities such as being serializable, clickable, comparable, or able to produce a result.
Mental Model
Think of a Kotlin class as a person with one family line and several skills.
- The superclass is the family line: the class can inherit from only one direct parent class.
- Interfaces are skills or contracts: the class can promise to support many of them.
For example, a ReportExporter might inherit common file-handling behavior from BaseExporter while also promising to support the Exportable and Loggable contracts.
Syntax and Examples
Use a colon after the class name. Put the superclass first, followed by interfaces.
abstract class SuperClass {
abstract fun process()
}
interface MyInterface {
fun save()
}
class MyClass : SuperClass(), MyInterface {
override fun process() {
println("Processing data")
}
override fun save() {
println("Saving data")
}
}
MyClass does two things:
- It extends
SuperClass, so it must implement the abstractprocess()function. - It implements
MyInterface, so it must implementsave().
If the parent class has constructor parameters, pass them when declaring the subclass:
abstract class SuperClass(val name: String)
interface MyInterface {
fun save()
}
class MyClass(name: String) : SuperClass(name), MyInterface {
override fun save() {
println("Saving $name")
}
}
Interfaces do not use constructor parentheses unless they are declared as a class-like type, which ordinary Kotlin interfaces are not.
Step by Step Execution
Consider this example:
abstract class Job {
abstract fun run()
}
interface Loggable {
fun log(message: String)
}
class BackupJob : Job(), Loggable {
override fun run() {
log("Backup started")
println("Copying files...")
log("Backup finished")
}
override fun log(message: String) {
println("LOG: $message")
}
}
fun main() {
val job = BackupJob()
job.run()
}
Execution proceeds as follows:
BackupJobis declared as a subclass ofJoband an implementation ofLoggable.- Because
Job.run()is abstract,BackupJobprovidesoverride fun run(). - Because
Loggable.log()has no implementation,BackupJobprovidesoverride fun log(...). maincreates aBackupJobobject.- Calling
job.run()prints log messages and the backup action.
Output:
LOG: Backup started
Copying files...
LOG: Backup finished
Real World Use Cases
Common uses of a superclass plus interfaces include:
- UI components: inherit shared behavior from a base component and implement click, focus, or lifecycle interfaces.
- API services: extend a base service that provides shared configuration while implementing an interface required by dependency injection or testing.
- Data import jobs: inherit shared job setup and implement interfaces such as
Runnable, a project-specificValidatable, or a reporting contract. - Domain models: extend a base entity with an ID and timestamps while implementing interfaces such as
Comparable. - Testing: extend a shared test fixture class while implementing a test-specific contract or callback interface.
For example, Kotlin classes frequently implement Java interfaces too:
class NameComparator : Comparator<String> {
override fun compare(a: String, b: String): Int {
return a.compareTo(b)
}
}
Real Codebase Usage
In production Kotlin code, developers often separate shared implementation from contracts:
abstract class BaseRepository {
protected fun requireId(id: String) {
require(id.isNotBlank()) { "id must not be blank" }
}
}
interface UserRepository {
fun findName(id: String): String?
}
class InMemoryUserRepository : BaseRepository(), UserRepository {
private val users = mapOf("u1" to "Ava")
override fun findName(id: String): String? {
requireId(id) // Shared base-class behavior
return users[id] // Interface contract
}
}
This pattern helps with:
- Dependency inversion: application code depends on
UserRepository, not the concrete implementation. - Testing: tests can substitute a fake implementation of an interface.
- Shared utilities: a base class can hold protected helper functions or common state.
- Guard clauses and validation: base classes can centralize validation, while subclasses provide specialized behavior.
Prefer an interface when you need a contract. Use an abstract base class only when subclasses genuinely need shared state or shared implementation.
Common Mistakes
Forgetting the superclass constructor call
A Kotlin class must call its superclass constructor when extending a class.
abstract class Parent
// Incorrect: Parent is a class, so its constructor call is required.
class Child : Parent, Runnable
Correct:
class Child : Parent(), Runnable {
override fun run() {}
}
Adding parentheses to an interface
interface Printable {
fun print()
}
// Incorrect
class Report : Printable() {
override fun print() {}
}
Correct:
class Report : Printable {
override fun print() {}
}
Forgetting override
Kotlin requires the override keyword when implementing or replacing an inherited member.
interface Printable {
fun print()
}
class Report : Printable {
// Incorrect: missing override
fun print() {}
}
Correct:
class Report : Printable {
override fun print() {}
}
Trying to extend two classes
Kotlin allows only one superclass.
open class First
open class Second
// Incorrect
// class Child : First(), Second()
Extract shared behavior into an interface, use composition, or choose one base class.
Ignoring conflicting interface default implementations
If two interfaces provide the same method implementation, the class must resolve the conflict explicitly.
interface A {
fun greet() = println("A")
}
interface B {
fun greet() = println("B")
}
class C : A, B {
override fun greet() {
super<A>.greet()
}
}
Comparisons
| Feature | Java | Kotlin |
|---|---|---|
| Extend a class | extends Parent | : Parent() |
| Implement an interface | implements Contract | : Contract |
| Extend a class and implement interfaces | extends Parent implements A, B | : Parent(), A, B |
| Number of direct superclasses | One | One |
| Number of implemented interfaces | Many | Many |
| Override keyword | Optional annotation, depending on compiler checks | Required: override |
A superclass and an interface serve different purposes:
| Choose | When you need |
|---|---|
| Abstract class | Shared state, constructor parameters, or partial implementation |
| Interface | A contract that many unrelated classes can implement |
| Composition | Reusable behavior without making one type inherit from another |
Cheat Sheet
// One superclass and one interface
class Child : Parent(), Contract {
override fun requiredFunction() {}
}
// One superclass and multiple interfaces
class Child : Parent(), ContractA, ContractB
// Parent constructor with arguments
class Child(id: Int) : Parent(id), Contract
// Interface only
class Child : ContractA, ContractB
Rules:
- A class may extend one direct class.
- A class may implement many interfaces.
- Put the superclass first in the colon list.
- Use
()for a superclass constructor call. - Do not use
()after a normal interface name. - Implement inherited abstract members with
override. - Resolve duplicate interface default methods with
super<InterfaceName>.method().
FAQ
Can a Kotlin class extend a class and implement an interface?
Yes. Use one colon and list the superclass followed by interfaces:
class MyClass : SuperClass(), MyInterface
Why does the superclass have parentheses in Kotlin?
The parentheses call the superclass constructor. Even a no-argument constructor is written as SuperClass().
Does an interface need parentheses in Kotlin inheritance syntax?
No. Use MyInterface, not MyInterface().
Can an abstract Kotlin class implement an interface?
Yes. It can implement all members, some members, or leave abstract members for subclasses to implement.
Can Kotlin extend multiple classes?
No. Kotlin supports one direct superclass, but a class can implement multiple interfaces.
Must I implement every interface function immediately?
A non-abstract class must implement all required abstract members. An abstract class may leave some members unimplemented.
What happens if the superclass and an interface define the same function?
A superclass implementation normally takes precedence. If multiple interfaces provide conflicting default implementations, override the function and choose which implementation to call with super<InterfaceName>.function().
Mini Project
Description
Build a small notification system. A base class supplies shared recipient information, while an interface defines the contract for sending a notification. This reflects a common design in applications that support email, SMS, push, or other delivery channels.
Goal
Create an email notification class that extends an abstract base class and implements a notification interface.
Requirements
- Create an abstract
BaseNotificationclass that stores a recipient. - Create a
Sendableinterface with asendfunction. - Create an
EmailNotificationclass that extends the base class and implements the interface. - Validate that the message is not blank before sending it.
- Create and send one email notification from
main.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Add a Maven Repository URL in Gradle Kotlin DSL (build.gradle.kts)
Learn how to add Maven Central and a custom Maven repository URL in Gradle Kotlin DSL using build.gradle.kts syntax.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.