Kotlin Interfaces

Learn via video courses
Topics Covered

Overview

Interfaces that solely contained static variables or methods without a body were available in Java. However, we may now have interfaces in Kotlin with functions that have a body. Kotlin permits an interface to contain code, allowing a class to implement it and derive its behaviour from it.

Creating Interfaces

Declaration for interface in Kotlin starts with the keyword interface, then the name of the interface, and finally the curly braces that house the members of the interface. The members won't have their own definitions, which is the distinction. The conforming types will offer the following definitions:

Example:

Defining the Interface

An interface in kotlin is defined using the keyword interface:

Implementing Interfaces

A class or an object can implement an interface in Kotlin. The conforming type must include definitions for each of its members when implementing an interface. In order to implement an interface in Kotlin, the name of the custom type is followed by a colon, followed by the name of the interface that is to be implemented. A class or object can implement one or more interfaces in Kotlin

Example:

Properties in Interfaces

Interfaces in Kotlin can also contain properties, much like methods.

There are no underlying fields to store their values because they cannot be instantiated since the interface lacks a state.

Let's understand this statement in depth.

A backing field is an internal, hidden storage mechanism that is responsible for holding the value of a property. Here, properties provide a way to define getter and setter methods so that we can access and modify the state of an object's fields while making sure the under-the-hood details of the same are abstracted.

So, backing fields store the actual value of a property apart from the methods with an aim to access it

Let's see an example,

Here, variable myProperty has a backing field automatically generated by Kotlin, and the get and set methods use a field identifier to refer to the backing field.

What if we didn't have these backing fields we've been talking about?

Interfaces are only limited to defining properties and not directly storing the state, which happens with the use of a backing field, so when the class implements an interface with a property, the class itself needs to provide its own backing storage and implementation for the said property.

Consider the following example,

Now whenever a class implements MyInterface, there's a need for it to provide its own backing field and implementation for myProperty. As a result, the interface's fields are either left abstract or given an implementation.

For Example:

Output:

Explanation:

InterfaceProperties in the program above specifies two properties, a of type integer and b of type String with a getter. The two properties are given value by the class PropertiesDemo, which implements InterfaceProperties and overrides the two properties. The class object is created by the method main, and dot-syntax (x.a) is used to access the properties.

Following the previous discussion let's conclude scenarios wherein interfaces can be useful:

  1. Abstraction:
    Interfaces offer a mechanism to specify a shared agreement across various classes without revealing the implementation specifics. You can then produce abstractions that make your code more modular and maintainable.
  2. Polymorphism:
    Interfaces enable polymorphic behavior by allowing the creation of objects of various types that have the same interface.
  3. Reusability of code:
    By enabling several classes to implement the same interface and share the same abstract methods and properties, interfaces offer a mechanism to reuse code.

Interfaces Inheritance

An interface in Kotlin can also inherit from another interface. Similar to interfaces, many implementations are supported. To clear up any confusion, this is simply multiple implementations and not multiple inheritances because multiple inheritance is not supported by Kotlin. Numerous skill sets for a class can be defined, which allows us to perform various implementations here. Consequently, a class can have several can-do relationships.A class can also inherit from several interfaces in the same way. We can add multiple skill sets to a class. The abstract methods and values of the interfaces in Kotlin that classes inherit must also be overridden. However, overriding inherited methods and variables in classes is no longer necessary if they have already been done so in child interfaces.

Resolving Overriding Conflicts

A class may inherit a function that has a default implementation for the same contract in various interfaces in Kotlin while implementing multiple interfaces. This brings up the issue of calling this function from an instance of the class that is doing the implementation. Kotlin requires the subclass to supply an overridden implementation for these functions in order to make the resolution of the conflict explicit.

Let's see an example:

Output:

A conflict arises because both BakeryItem and Pastry interfaces have methods named type(). When a class implements both interfaces and tries to override the conflicting method, Kotlin requires you to explicitly specify which version of the method you want to call using super<InterfaceName>.methodName(). In this example, super<BakeryItem>.type() and super<Pastry>.type() are used in Shop to differentiate and call the methods from the respective interfaces. 

This approach to interface inheritance provides modularity and reusability to the code.While managing conflicts during method overriding might appear challenging initially, it's crucial to recognize that Kotlin's rigorous method requires it, ultimately leading to code that's clear and unequivocal.

Example to Demonstrate an Interface in Kotlin

Output

Explanation:

The interface Vehicle in this program declares two methods, start() and stop(), which must be overridden. The interface in kotlin here is implemented by the class Car using the class-literal syntax, and the override keyword is used to replace the two methods. The two methods are then called by the main function, which also produces an object of the class Car.

Default Values and Default Methods

A method's parameters in an interface in kotlin may have default values. When calling a function, the default value is utilized if a parameter's value is not specified. The methods may also come with default versions. When the method is not overridden, these are applied.

Example:

Output:

Explanation:

The FirstInterface in the program above defines the two methods add() and print(). Two parameters are available for the add() method, one of which has a default value of 5. A default implementation of the print() method is additionally included. As a result, when class InterfaceDemo implements the interface, it calls the default implementation of print() and overrides both methods. Additionally, when invoking the add method in the main function, only one parameter is needed because the second one is given a default value.

Conclusion

  1. An interface in Kotlin is a set of abstract methods and attributes that provide a shared agreement for classes that implement it
  2. Kotlin requires the subclass to supply an overridden implementation for these functions in order to make the resolution of the conflict explicit
  3. A class can also inherit from several interfaces in the same way. We can add multiple skill sets to a class.
  4. A class or an object can implement an interface. The conforming type must include definitions for each of its members when implementing an interface.
  5. In Kotlin, the interface declaration starts with the keyword interface, then the name of the interface, and finally the curly braces that house the members of the interface.