Inheritance, Interfaces & Abstract Classes in Kotlin

Eren Mollaoğlu
4 min readJan 20, 2024

--

Interface & Inheritance & Abstract Classes

Inheritance

In Kotlin, when one class is derived from another, it is termed inheritance. By default, all classes implicitly inherit from the Any class. However, in Kotlin, classes are marked as final by default, meaning they cannot be inherited. If you wish to allow a class to be inherited, you must explicitly use the open keyword at the beginning of the class declaration.

// If inheritance class have parameter, must put this parameter when derived.
open class Animal(val age: Int)
class Dog : Animal(10)

// Constructors usage;
open class Vehicle() {
constructor(vehicleWeight: Int) : this()
constructor(vehicleWeight: Int, vehicleWheelCount: Int) : this()
}
class DerivedWithSecondaryConstructor : Vehicle {
constructor(vehicleWeight: Int) : super(vehicleWeight)
constructor(vehicleWeight: Int, vehicleWheelCount: Int) : super(
vehicleWeight,
vehicleWheelCount
)
}

If you want override methods, you must put open keyword start of function just like class.

open class Book {
open var pageNumber: Int = 10
open fun addPage() {
pageNumber++
}

fun writeOnPage(text: String) {
println(text)
}
}

open class WorkBook : Book() {
override var pageNumber: Int
get() = super.pageNumber
set(value) {}
// If we don't want more override method, can put 'final' keyword
final override fun addPage() {
super.addPage()
}
// We cant override writeOnPage because this method can't marked with 'open'.
}

class MathWorkBook : WorkBook() {
// In here pageNumber can overridable but addPage can't because it defined as 'final'
override var pageNumber: Int
get() = super.pageNumber
set(value) {}
}

During the initialization process, the derived class first provides parameters to the base class. Subsequently, the initialization and properties of the base class are processed, followed by the initialization and properties of the derived class in order.

open class Plane(companyName: String) {
init {
println("init in plane")
}

open val companyNameLength: Int = companyName.length.also {
println("nameLength in plane")
}
}

class SmallPlane(companyName: String) :
Plane(companyName.also { println("argument initialization") }) {
init {
println("init in SmallPlane")
}
override val companyNameLength: Int = super.companyNameLength.also {
println("nameLength in SmallPlane")
}
}
fun main(){
val sp = SmallPlane("Turkish Airlines")

/*
OUTPUT:
argument initialization
init in plane
nameLength in plane
init in SmallPlane
nameLength in SmallPlane
*/
}

Interfaces

Interfaces contain common abstract methods or properties that classes have. They can implemented by class or interfaces. Interfaces similar to abstract class but they can implemented more than one class and they cant have states:

interface Peoples {
fun eat()
fun sleep()
val name: Int
}

The classes that implement the interface must override all methods. Properties defined in interfaces cannot have backing fields:

class Woman : Peoples {
override fun eat() {}
override fun sleep() {}
override val name: Int
get() = 1
}

An interface in Kotlin can implement another interface. This means that the classes implementing these interfaces are not required to provide their own implementations for the properties they inherit:

interface Man : Peoples {

override val name: Int
get() = parseType(mappedName)

val mappedName: String

override fun eat() {
TODO("Not yet implemented")
}
}

class Eren(override val mappedName: String):Man{
// Must be overriden
override fun sleep() {
TODO("Not yet implemented")
}
// Optional
override val name: Int
get() = super.name
override fun eat() {
super.eat()
}
}

In this state, there’s no need to override the type, but access to the properties of the type, such as mappedName, is allowed. The sleep method must be overridden because the Man interface cannot implement it directly.

A class in Kotlin can implement more than one interface, even if those interfaces have methods with the same names. To disambiguate, you can use the super<Class> syntax to specify which interface's method you want to call.

If an interface method doesn’t have a body, it’s considered ‘abstract,’ and you cannot call it directly. Instead, the implementing class must override this method to provide its own implementation:

interface Taxi {
fun takeCustomer() { println("taxi takes customer") }
fun dropCustomer() { println("taxi drops customer") }
}

interface Boat {
fun takeCustomer() { println("boat takes customer") }
fun dropCustomer()
fun mustOverride()
}

class SeaTaxi : Taxi, Boat {
override fun takeCustomer() {
super<Taxi>.takeCustomer()
super<Boat>.takeCustomer()
}
override fun dropCustomer() {
super<Taxi>.dropCustomer()
// Abstract member cannot be accessed directly
// super<Human>.sleep()
}
override fun mustOverride() { TODO("Not yet implemented") }

If a interfaces function have body then override is optional.

Abstract Classes

A abstract classes is used for share common implementations to the classes that derive from it. Self-inheriting classes override all functions that are abstract. they have to.

Its object cannot be produced. Each one properties and member functions are non-abstract by default. If these functions or properties wanted to override they must marked with open keyword. If function already marked with abstract then open keyword is unnecessary they are open by defaultly.

interface AnimationListener {
fun onStart()
fun onResume()
fun onDestroy()
}

abstract class AnimationContract : AnimationListener {
override fun onStart() {}
override fun onResume() {}
override fun onDestroy() {}
abstract fun restartAnimation()
}

class Animation: AnimationContract() {
override fun restartAnimation() {
TODO("Not yet implemented")
}

}

Abstract classes can be likened to template classes, behaving as drafts that outline the structure without providing a full implementation. By abstracting away the implementation details of interfaces, these classes contribute to code organization and prevent redundancy. Abstract classes also facilitate polymorphism, allowing you to define methods that take objects of a broader class, and then use objects of classes that inherit from it. In simpler terms, abstract classes serve as blueprints, promoting code reuse and flexibility through inheritance.

Finish;

I may have mistakes, I apologize if I have mistakes, if you think I have mistakes, you can contact me. Thank you all for reading, Happy coding…

My Social Accounts;

And also you can reach me in eren.mollaoglu@outlook.com mail address.

Sources;

--

--