In this tutorial, you’ll learn about inheritance. All the more explicitly, what is inheritance and how to implement it in Kotlin (with the assistance of examples).
Inheritance is a feature using which a class inherits every one of the highlights of another class. The class from which the highlights are inherited is known as base class or super class or parent class and the class that inherits the highlights is known as a derived class or sub class or child class.
Inheritance is one of the key highlights of object-oriented programming. It allows the user to create another class (derived class) from a current class (base class).
The determined class acquires every one of the highlights from the base class and can have extra highlights of its own.
Prior to going into details regarding Kotlin inheritance, we recommend you to check these two tutorials:
In this article, you will learn-
Why inheritance?
Assume, in your application, you need three characters – a math teacher, a footballer, and a businessman.
Since the entirety of the characters is people, they can walk and talk. In any case, they additionally have some uncommon abilities. A math teacher can teach math, a footballer can play football and a businessman can run a business.
You can individually create three classes who can walk, talk and play out their special skills.
In every one of the classes, you would duplicate a similar code to walk and talk for each character.
On the off chance that you need to add another feature – eat, you need to execute a similar code for each character. This can undoubtedly become error-prone (when copying) and copy codes.
It would be significantly simpler in the event that we had a Person class with essential highlights like talk, walk, eat, rest, and add special skills to those highlights according to our characters. This is finished using inheritance.
Using inheritance, presently you don’t carry out a similar code for walk(), talk() and eat() for each class. You simply need to inherit them.
In this way, for MathTeacher (derived class), you acquire all highlights of a Person (base class) and add another component teachMath(). Moreover, for the Footballer class, you acquire every one of the highlights of the Person class and add another element playFootball, etc.
This makes your code cleaner, understandable and extendable.
It is imperative to recollect: When working with inheritance, each derived class ought to satisfy the condition whether it “is a” base class or not. In the example above, MathTeacher is a Person, Footballer is a Person. You can’t have something like, Businessman is a Business.
Kotlin inheritance
Let’s try to implement the above discussion in code:
open class Person(age: Int) { // code for eating, talking, walking } class MathTeacher(age: Int): Person(age) { // other features of math teacher } class Footballer(age: Int): Person(age) { // other features of footballer } class Businessman(age: Int): Person(age) { // other features of businessman }
Here, Person
is a base class, and classes MathTeacher
, Footballer
, and Businessman
are derived from the Person class.
Notice, the keyword open
before the base class, Person
. It’s important.
By default, classes in Kotlin are final. If you are familiar with Java, you know that a final class cannot be subclassed. By using the open annotation on a class, compiler allows you to derive new classes from it.
Example: Kotlin Inheritance
open class Person(age: Int, name: String) { init { println("My name is $name.") println("My age is $age") } } class MathTeacher(age: Int, name: String): Person(age, name) { fun teachMaths() { println("I teach in primary school.") } } class Footballer(age: Int, name: String): Person(age, name) { fun playFootball() { println("I play for Test.") } } fun main(args: Array<String>) { val t1 = MathTeacher(25, "Salman") t1.teachMaths() println() val f1 = Footballer(29, "Sohail") f1.playFootball() }
At the point when you run the program, the output will be:
My name is Salman. My age is 25 I teach in primary school. My name is Sohail. My age is 29 I play for Test.
Here, two classes, MathTeacher and Footballer are derived from the Person class.
The essential constructor of the Person class announced two properties: age and name, and it has an initializer block. The initializer block (and part elements) of the base class Person can be accessed by the objects of derived classes (MathTeacher and Footballer).
Determined classes MathTeacher and Footballer have their own part capacities teachMaths() and playFootball() respectively. These functions are open just from the objects of their particular class.
At the point when the object t1 of MathTeacher class is created,
val t1 = MathTeacher(25, "Salman")
The parameters are passed to the essential constructor. In Kotlin, the init block is considered when the object is created. Since MathTeacher is derived from the Person class, it searches for the initializer block in the base class (Person) and executes it. In the event that the MathTeacher had to init block, the compiler would have likewise executed the init block of the derived class.
Then, the teachMaths() work for object t1 is called using t1.teachMaths() statement.
The program works also when object f1 of Footballer class is created. It executes the init block of the base class. At that point, the playFootball() technique for Footballer class is called using statement f1.playFootball().
Significant Notes: Kotlin Inheritance
In the event that the class has an essential constructor, the base should be introduced using the parameters of the essential constructor. In the above program, both derived classes have two parameters age and name, and both these parameters are introduced in the essential constructor in the base class.
Here’s another example:
open class Person(age: Int, name: String) { // some code } class Footballer(age: Int, name: String, club: String): Person(age, name) { init { println("Football player $name of age $age and plays for $club.") } fun playFootball() { println("I am playing football.") } } fun main(args: Array<String>) { val f1 = Footballer(29, "Sohail", "for Test")
Here the essential constructor of the determined class has 3 parameters, and the base class has 2 parameters. Note that, the two parameters of the base class are instated.
If there should be an occurrence of no essential constructor, each base class needs to instate the base (using super catchphrase), or delegate to another constructor which does that. For instance,
fun main(args: Array<String>) { val p1 = AuthLog("Bad Password") } open class Log { var data: String = "" var numberOfData = 0 constructor(_data: String) { } constructor(_data: String, _numberOfData: Int) { data = _data numberOfData = _numberOfData println("$data: $numberOfData times") } } class AuthLog: Log { constructor(_data: String): this("From AuthLog -> + $_data", 10) { } constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) { } }
To learn more on how this program works, visit Kotlin Secondary Constructor.
Overriding Member Functions and Properties
On the off chance that the base class and the derived class contains a member function (or property) with a similar name, you can have to override the member function of the determined class using supersede watchword and use an open catchphrase for the member function of the base class.
Example: Overriding Member Function
// Empty primary constructor open class Person() { open fun displayAge(age: Int) { println("My age is $age.") } } class Girl: Person() { override fun displayAge(age: Int) { println("My fake age is ${age - 5}.") } } fun main(args: Array<String>) { val girl = Girl() girl.displayAge(31) }
At the point when you run the program, the output will be:
My fake age is 26.
Here, girl.displayAge(31) calls the displayAge() method of the derived class Girl.
You can override the property of the base class in a similar way.
Visit how Kotlin getters and setters work in Kotlin before you check the example below.
// Empty primary constructor open class Person() { open var age: Int = 0 get() = field set(value) { field = value } } class Girl: Person() { override var age: Int = 0 get() = field set(value) { field = value - 5 } } fun main(args: Array<String>) { val girl = Girl() girl.age = 31 println("My fake age is ${girl.age}.") }
At the point when you run the program, the output will be:
My fake age is 26.
As should be obvious, we have used supersede and open catchphrases for age property in derived class and base class respectively.
Calling Members of Base Class from Derived Class
You can call functions (and access properties) of the base class from a derived class using super catchphrase. Here’s how:
open class Person() { open fun displayAge(age: Int) { println("My actual age is $age.") } } class Girl: Person() { override fun displayAge(age: Int) { // calling function of base class super.displayAge(age) println("My fake age is ${age - 5}.") } } fun main(args: Array<String>) { val girl = Girl() girl.displayAge(31) }
At the point when you run the program, the output will be:
My age is 31. My fake age is 26.
Thanks for reading! We hope you found this tutorial helpful and we would love to hear your feedback in the Comments section below. And show us what you’ve learned by sharing your photos and creative projects with us.