Inheritance is a fundamental concept in object-oriented programming (OOP) that allows you to create new classes based on existing classes, thereby promoting code reuse and the organization of related classes in a hierarchy. Kotlin supports inheritance, and in this guide, we’ll explore how to use it effectively in Kotlin, including the syntax, overriding methods, and accessing superclass members.
Defining a Superclass
In Kotlin, you define a superclass using the class
keyword, just like you would for any other class. A superclass typically contains properties and methods that are common to its subclasses. Here’s a basic example of a superclass called Shape
:
open class Shape {
open fun area(): Double {
return 0.0
}
}
In this example, Shape
is a simple class with a method area()
, which calculates the area of a shape. The open
keyword before the class declaration and the open
keyword before the area()
method indicate that they can be overridden by subclasses.
Creating a Subclass
To create a subclass in Kotlin, you use the :
symbol followed by the name of the superclass in the class header. Subclasses inherit properties and methods from their superclass. Here’s an example of a Circle
subclass that inherits from the Shape
superclass:
class Circle(val radius: Double) : Shape() {
override fun area(): Double {
return Math.PI * radius * radius
}
}
In this example, Circle
is a subclass of Shape
, and it overrides the area()
method to provide its own implementation for calculating the area of a circle.
The super
Keyword
In Kotlin, you can use the super
keyword to access members (properties or methods) of the superclass within a subclass. This is useful when you want to invoke the superclass’s implementation of a method that you’ve overridden. Here’s an example:
open class Animal(val name: String) {
open fun makeSound() {
println("$name makes a sound")
}
}
class Dog(name: String) : Animal(name) {
override fun makeSound() {
super.makeSound() // Calls the makeSound() method of the superclass
println("$name barks")
}
}
In this example, the Dog
class inherits from the Animal
superclass and overrides the makeSound()
method. Inside the overridden method, super.makeSound()
is used to call the makeSound()
method of the Animal
superclass before adding its own behavior.
Overriding Rules
In Kotlin, when you override a member (method or property) of a superclass in a subclass, you must follow some rules:
- The overridden member in the subclass must have the
override
modifier. - The signature of the overridden member in the subclass must match the signature of the superclass member, including the name, return type, and parameter types.
- If the superclass member is marked as
open
,abstract
, orinterface
, it can be overridden. - You can use the
super
keyword to call the overridden member of the superclass within the subclass.
Polymorphism
Polymorphism is a key concept in inheritance, allowing you to work with objects of different classes in a unified way. In Kotlin, you can take advantage of polymorphism when dealing with class hierarchies. Here’s an example:
fun printArea(shape: Shape) {
println("Area: ${shape.area()}")
}
fun main() {
val circle = Circle(5.0)
val square = Square(4.0)
printArea(circle)
printArea(square)
}
In this code, the printArea
function takes a Shape
object as an argument and prints its area. It can work with both Circle
and Square
objects because they inherit from Shape
. This is an example of polymorphism, where objects of different subclasses can be treated as objects of the superclass.
Abstract Classes
In addition to regular classes, Kotlin allows you to define abstract classes. An abstract class is a class that cannot be instantiated on its own but can be used as a blueprint for other classes. Abstract classes may contain abstract methods, which are declared without implementation and must be overridden by subclasses. Here’s an example:
abstract class Shape {
abstract fun area(): Double
}
class Circle(val radius: Double) : Shape() {
override fun area(): Double {
return Math.PI * radius * radius
}
}
class Square(val sideLength: Double) : Shape() {
override fun area(): Double {
return sideLength * sideLength
}
}
In this example, the Shape
class is abstract, and it defines an abstract method area()
. Subclasses Circle
and Square
provide their own implementations of the area()
method. Abstract classes are useful for creating class hierarchies where certain methods need to be implemented by all subclasses.
Command and Example
Here’s a complete example that demonstrates inheritance and polymorphism in Kotlin:
open class Shape {
open fun area(): Double {
return 0.0
}
}
class Circle(val radius: Double) : Shape() {
override fun area(): Double {
return Math.PI * radius * radius
}
}
class Square(val sideLength: Double) : Shape() {
override fun area(): Double {
return sideLength * sideLength
}
}
fun main() {
val circle = Circle(5.0)
val square = Square(4.0)
println("Circle Area: ${circle.area()}")
println("Square Area: ${square.area()}")
}
In this example, we have a superclass Shape
with an area()
method and two subclasses, Circle
and Square
, that override the area()
method to provide their own implementations. The main()
function demonstrates creating objects of both subclasses and invoking the area()
method on them, showcasing how polymorphism allows for a unified approach to working with different shapes.