Design Converter
Education
Last updated on Aug 2, 2024
•9 mins read
Last updated on May 1, 2024
•9 mins read
Understanding inheritance in the realm of object-oriented programming is essential. Kotlin class inheritance, a concept rooted in object-oriented programming, allows new classes to inherit fields and methods from existing classes. This feature promotes code reusability, making your code easier to maintain.
In Kotlin, class inheritance provides the existing class, often known as the parent class or base class, with a mechanism to share its characteristics with new classes, referred to as child classes or derived classes. Inheritance implies that a derived class inherits the properties and behaviors of a base class, permitting the reuse of common code.
Consider this simple class example:
1open class Base(val name: String) //base class 2 3class Derived(name: String) : Base(name) //derived class
In the given example, the base class Base has a primary constructor which accepts a name string. The derived class Derived takes on the same properties by using the same name in its primary constructor, demonstrating Kotlin class inheritance.
An essential aspect of Kotlin inheritance is the base class. It serves as the class from which all the derived classes inherit its properties or features. A base class's characteristics and member functions become the default superclass for all new classes, setting the foundation for every derived class.
Here's an example of how a base class secondary constructor contributes to Kotlin inheritance:
1open class Base { //base class 2 constructor(name: String) { //secondary constructor 3 println("Name is $name") 4 } 5} 6 7class Derived : Base { //derived class inherits 8 constructor(name: String): super(name) 9}
In this case, the Base class has a secondary constructor requiring a name string. The class Derived extends (is derived from) Base. This class derived provides a name to the base class constructor, adopting all the features of the base class.
Derived classes are pivotal to Kotlin class inheritance. In the fundamental sense, whenever we declare a new class inheriting from an existing class, we create a derived class. Along with the inherited properties, derived classes can also introduce new properties.
Let's consider an example:
1open class Base(val name: String) //base class 2class Derived(name: String, val id: Int) : Base(name) //derived class
Our base class, Base, takes a single val name string parameter in its primary constructor. On the other hand, our derived class, Derived, requires an extra id parameter in addition to the name. Here, we can see that although the Derived class inherits the properties of the Base class, it also introduces new properties.
To extend this concept further, we introduce the open keyword, the override modifier, and the fun main:
1open class Base(name: String) { //open class base 2 var color: String = name //var property 3 open fun draw() { } //member function open fun 4} 5 6class Derived(name: String) : Base(name) { //inherit properties 7 override fun draw() { } //override fun 8} 9 10fun main() { //fun main 11 val d = Derived("green") 12 d.draw() 13}
Here, Base is an open class (a class that can be inherited), and Derived is a final class (a class that cannot be inherited). The draw function in Base is overridable due to the open modifier, so the Derived class can provide its implementation of draw() using the override keyword.
In the fun main, we created an instance of Derived and called the draw function. Depending upon the implementation, either the draw function from the Base or the Derived will be called, demonstrating method overriding in Kotlin.
Note: In Kotlin, classes are final by default. If you want to make a class inheritable, you have to mark it with the keyword open.
One significant aspect of the Kotlin extends class is that there's no extended keyword in Kotlin. Instead, the colon (:) is used to indicate inheritance. A derived class is declared by placing a colon after the class name, followed by the name of the base class.
1open class Base(val name: String) //base class 2class Derived(name: String) : Base(name) //derived class
In the code snippet above, the Derived class extends or inherits from the Base class. This example goes further to demonstrate that Kotlin inherits class scenarios. The derived class can also override member functions and properties of an existing base class. Here’s how we can override a member function of the base class:
1open class Shape { // open class shape 2 open fun draw() { } // open fun draw 3 fun fill() { } 4} 5 6class Circle() : Shape() { // class circle 7 override fun draw() { } // override fun draw 8}
In this code snippet, the Shape class is declared open, which makes this class inheritable, and the draw function is declared open as well. This tells Kotlin that we allow derived classes to override this function. The Circle class is a derived class that overrides the draw function from the Shape class using the override keyword.
In Kotlin, there’s a special type of class called data class. Typically, the purpose of a data class is to hold data. However, like any other Kotlin classes, it can also participate in inheritance:
1open class Base(val name: String, val id: Int) //open class base 2 3data class Derived(val name: String, val id: Int, val color: String) : Base(name, id) //data class derived
In the code above, Base is a simple open class with two properties. Derived is a data class that extends Base and adds property color.
The notion of extending a class is pivotal in Kotlin. Rather than physically extending the classes (as you might in Java), Kotlin provides a feature called “Extension Functions” that allows you to extend an existing class with new functionality.
1fun String.hasSpaces(): Boolean { 2 val found = this.indexOf(" ") 3 return found >= 0 4} 5 6fun main() { //fun main 7 val s = "Hello, Kotlin" 8 println(s.hasSpaces()) //prints true 9}
This function hasSpaces extends the String class and gives it a new function hasSpaces(). Here, we've added a new function to an existing type that determines whether the String contains spaces or not.
Let’s consider a real-world problem where extends in Kotlin can be of use. Suppose we have a same-named function display in the child class and parent class. You want the child class function to be invoked only, using a child class object. By using the extends concept, we can easily achieve this:
1open class A{ 2 open fun display() { print("A") } // open fun 3} 4 5class B: A() { 6 override fun display() { print("B") } // override fun 7} 8 9fun main() { // fun main 10 val obj = B() 11 obj.display() 12}
In the code above, both Class A and Class B have a function named display. The open keyword indicates that the display function from Class A is open for modification. Class B extends Class A: it inherits all the properties and functions from Class A and overrides the display function.
In Kotlin, there are certain pitfalls to avoid and best practices to follow while using Kotlin class inheritance.
Class Final By Default: Remember that in Kotlin, all classes are final by default. Hence, if you want to make a class inheritable, it must be declared as open.
Sealed Classes: Seal your class if you want it to have a limited hierarchy. Sealed classes in Kotlin can only be subclassed within the same module, providing a safe, controlled way of using inheritance.
Avoid Redundancy with Interface: Use interfaces to avoid redundancy. An interface can be implemented by multiple classes, so you can use an interface to derive multiple implementations.
Respect Liskov Substitution Principle: Coding to an interface, or more high-level classes, rather than concrete implementations is generally considered a best practice. Kotlin respects Liskov’s Substitution Principle (LSP), a basic rule of inheritance that promotes substitutability and reliability.
To conclude, Kotlin class inheritance is a powerful tool for versatile and maintainable code. While it might take a moment to get used to the syntax, understanding the concept can lead to cleaner and more efficient code. Whether you're overriding member functions or extending existing classes with new functions, Kotlin offers a robust and versatile set of tools for class inheritance. Embrace Kotlin class inheritance and bring a whole new level of reusability and extensibility to your code.
For further understanding and exploration of Kotlin class inheritance, consider reviewing the resources mentioned below. They cover topics ranging from the basics of Kotlin classes to the advanced functionality of Kotlin inheritance, including common superclass, sealed classes, and more.
• Kotlin Language Documentation: Inheritance
• Kotlin Programming: The Big Nerd Ranch Guide
• Kotlin in Action by Dmitry Jemerov and Svetlana Isakova
• Kotlin for Android Developers: Learn Kotlin while developing an Android App by Antonio Leiva
As with any programming language, hands-on practice makes perfect in Kotlin. Irrespective of the keywords, modifiers, or special syntax, the best way to grasp the mechanism and the nuances of Kotlin class inheritance is to create and experiment with as many Kotlin classes and inheritance structures as possible. JetBrains provides an excellent interactive environment for this in the form of Kotlin Playground.
Frameworks like Spring Boot also have comprehensive support for Kotlin, and trying to build traditional Spring applications while taking advantage of all the features Kotlin will widely help solidify your understanding of Kotlin inheritance.
Achieving the balance between code reusability, maintainability, and avoiding the abuse of inheritance is what makes a Kotlin developer stand out. Happy Kotlin Learning!
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.