Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Inheritance and Interfaces | Object-Oriented Programming in Kotlin
Android Development with Kotlin
course content

Course Content

Android Development with Kotlin

Android Development with Kotlin

1. Kotlin Basics
2. Control Flow and Collections
3. Object-Oriented Programming in Kotlin

Inheritance and Interfaces

In OOP, there are certain principles and functionalities to follow. These principles help in writing more convenient and flexible code.

Let's go over these principles.

OOP Principles

There are three main principles, so let's briefly cover each one:

  • Inheritance: Inheritance allows a new class (subclass) to inherit the properties and methods of an existing class (superclass). This promotes code reuse and establishes a hierarchical relationship between classes.
    For example, if you have a superclass Animal that defines properties and attributes common to most animals, you can have a subclass Dog that inherits from this superclass and adopts its properties. This helps maintain proper code structure and enhances flexibility;
  • Polymorphism: Polymorphism allows objects to be treated as instances of their parent class, even if they are instances of a child class. It enables a single function or method to work in different ways depending on the object it operates on.
    For example, the Animal class might have a makeSound function(method) representing the animal's sound. The Dog subclass would also have a sound, which might be a "bark." Polymorphism allows us to inherit the property from the superclass but override and customize it for the subclass;
  • Encapsulation: Encapsulation is the bundling of data (properties) and methods (functions) that operate on the data into a single unit or class. It also involves restricting access to some of the object's components, meaning the internal representation of an object is hidden from the outside. This is typically achieved using access modifiers like private, protected, and public.

We will discuss encapsulation and polymorphism in more detail in the next chapters, as these are important principles that need closer examination.

Note

There’s also a fourth, often overlooked principle in OOP—Abstraction. Abstraction tells us to depend on abstractions rather than concrete implementations. We’ll discuss abstract classes and fields in more detail later on.

In summary, the three OOP principles are as follows:

Inheritance

Let’s talk more about inheritance in Kotlin and how it is achieved.

We’ll look at the main concepts, focusing on two classes that will have a specific relationship with each other.

Base (Parent) Class:

The base class is the class whose properties and methods are inherited by another class. In Kotlin, all classes are final by default, meaning they cannot be inherited unless explicitly marked as open.

Derived (Child) Class:

The derived class inherits properties and methods from the base class and can also have additional properties or methods. You can override base class methods in the derived class to provide specific functionality.

Note

Method overriding means that a specific method will have different, overridden functionality in the class where it was overridden. For example, if in the parent class, the method displays "Hello, World!" on the screen, in the child class, the overridden method might display a different text, like "Hello, Country!". Once you see an example, it will become clearer how this works.

Let's start with an example where we have a base class, Animal, and two derived classes, Dog and Cat.

Base (Parent) class Animal:

kt

Animal

copy
123456789
open class Animal(val name: String, val age: Int) { fun sleep() { println("$name is sleeping") } open fun makeSound() { println("$name makes a sound") } }

As you can see, the class is created using the open keyword, indicating that this class can be inherited and that it is a base class.

You might also notice that the second method, makeSound(), is also marked as open. This means the method can be overridden, which we will do later in the child classes.

Now, let's look at the creation of the child class Dog:

kt

Dog

copy
123456789
class Dog(name: String, age: Int) : Animal(name, age) { fun bark() { println("$name is barking") } override fun makeSound() { println("$name barks") } }

In Kotlin, when a class inherits from another class, the child class needs to pass information to the parent class. This is done using : ParentClass(parameters) right after the child class's name. It tells Kotlin first to set up the parent class with those parameters.

For example, when you create a Dog from Animal, Dog("Buddy", 3) : Animal("Buddy", 3) passes "Buddy" and 3 to Animal first, setting up name and age.

Here, you can also see how overriding works. The function that was marked as open in the parent class is overridden here, and instead of $name makes a sound, the function called from the Dog class will output $name barks, since dogs typically bark.

So, inheritance allows Dog to use the same base structure (name, age) but also customize behavior (bark instead of a generic sound).

Interface

Inheritance is closely related to interfaces in Kotlin.

In Kotlin, interfaces define a contract that classes implementing the interface must adhere to. Interfaces specify methods and properties that must be implemented but do not contain specific implementations, only their declarations.

Here’s how it works: the interface will only declare the methods, and the implementing class must inherit and override them, providing specific implementations.

Let’s look at an example of declaring an interface:

kt

Main

copy
1234
interface AnimalActions { fun makeSound() fun move() }

An interface is created using the interface keyword. Inside the interface, you can declare methods and properties that must be implemented in the classes. Each method in the interface must be open because classes will need to override them.

To implement an interface, a class uses the : symbol and must provide implementations for all the methods declared in the interface.

If the class fails to implement any of the methods, it will trigger an exception that will halt the service or program.

Let's look at an example class implementing the AnimalActions interface:

kt

Main

copy
123456789
class Dog : AnimalActions { override fun makeSound() { println("Bark") } override fun move() { println("Run") } }

We don't need to pass any data into the interface constructor, as we did when inheriting a class. When implementing an interface, we only override all the methods in the implementing class.

Additionally, Kotlin supports multiple inheritance of interfaces, for example:

kt

Main

copy
12345678910111213141516171819202122
interface AnimalActions { fun makeSound() fun move() } interface PetActions { fun play() } class Cat : AnimalActions, PetActions { override fun makeSound() { println("Meow") } override fun move() { println("Walk") } override fun play() { println("Chase a laser pointer") } }

As you can see, we created two interfaces that define certain behaviors for animals. The Cat class inherited these interfaces and overrode the methods from both interfaces, customizing the inherited methods for itself.

Inheriting Properties from Interfaces

Earlier, I mentioned that we shouldn't pass properties to the interface through a constructor because we handle this differently.

If the interface specifies certain properties, we must inherit and override them in the derived classes.

Here's how it looks in the code:

kt

Main

copy
1234567
interface AnimalInfo { val species: String } class Dog : AnimalInfo { override val species = "Canine" }

Summary

Inheritance is a crucial aspect and principle of OOP. It lets you structure your code the way you want.

Additionally, using interfaces, we can separate implementation and abstraction into distinct classes (interfaces) to distinguish between declaration and implementation.

In the following chapters, we will discuss the other two OOP principles and examine their implementation in Kotlin.

1. What keyword is used in Kotlin to allow a class to be inherited?
2. What is the purpose of an interface in Kotlin?

What keyword is used in Kotlin to allow a class to be inherited?

Select the correct answer

What is the purpose of an interface in Kotlin?

Select the correct answer

Everything was clear?

Section 3. Chapter 2
We're sorry to hear that something went wrong. What happened?
some-alt