You are currently viewing Kotlin Interface

Kotlin Interface

Interface

An interface is a blueprint for a class. An interface defines a set of abstract methods (methods without a body) and possibly some constants (static final fields). It provides a way to declare the behavior that implementing classes should adhere to, without providing the implementation details.

In Kotlin, you define an interface using the interface keyword:

interface MyInterface {
    // Abstract method declaration
    fun doSomething()

    // Property declaration (can be abstract or have a default implementation)
    val property: Int

    // Default implementation for a method (optional)
    fun defaultMethod() {
        println("Default implementation of defaultMethod")
    }
}

Let’s break down the syntax elements:

  • interface: Keyword indicating the declaration of an interface.
  • MyInterface: Name of the interface.

Inside the interface body, you can declare abstract methods (methods without a body), properties (abstract or with a default implementation), and provide default implementations for methods.

To implement this interface in a class, you can use the : InterfaceName syntax:

class MyClass : MyInterface {
    override fun doSomething() {
        println("Doing something")
    }

    override val property: Int
        get() = 42
}

In this example, MyClass implements MyInterface and provides concrete implementations for the abstract method doSomething and the property property

Here are some key points about Interface in Kotlin:

  1. Abstract Methods: Interfaces can contain abstract methods(methods without a body). Classes implementing the interface must provide concrete implementations for these methods.
  2. Properties: Interfaces can declare properties, which can be either abstract or have default implementations. Properties declared in interfaces are abstract by default.
  3. Multiple Inheritance: In many programming languages, including Kotlin and Java, a class can implement multiple interfaces. This enables a form of multiple inheritance.
  4. Default Implementations: Starting from Kotlin 1.0, interfaces can provide default implementations for methods, allowing implementing classes to use the default implementation or override the method.
  5. Companion Objects: An interface can have a companion object, allowing it to declare properties and functions that are associated with the interface itself rather than an instance of the implementing class.
  6. Functional Interfaces: Kotlin interfaces can represent functional interfaces, which are interfaces with a single abstract method. These can be used for functional programming constructs like lambda expressions.
  7. Constants: Interfaces can declare constants using val declarations in companion object, which can be accessed using the interface name.
  8. Type Hierarchy: Interfaces can be used to define common behavior and establish a type hierarchy, facilitating polymorphism.

Example of Interface in Kotlin

Let’s consider a real-world example of using interfaces in Kotlin within the context of a simple media player application. We’ll define an interface MediaPlayer that represents the common functionalities expected from various types of media players.

// Interface defining the MediaPlayer contract
interface MediaPlayer {
    fun play()
    fun pause()
    fun stop()
    fun skipToNext()
    fun skipToPrevious()
}

// Class representing a basic audio player
class AudioPlayer : MediaPlayer {
    override fun play() {
        println("Audio player is playing.")
    }

    override fun pause() {
        println("Audio player is paused.")
    }

    override fun stop() {
        println("Audio player is stopped.")
    }

    override fun skipToNext() {
        println("Skipping to the next track in the audio player.")
    }

    override fun skipToPrevious() {
        println("Skipping to the previous track in the audio player.")
    }
}

// Class representing a basic video player
class VideoPlayer : MediaPlayer {
    override fun play() {
        println("Video player is playing.")
    }

    override fun pause() {
        println("Video player is paused.")
    }

    override fun stop() {
        println("Video player is stopped.")
    }

    override fun skipToNext() {
        println("Skipping to the next video in the video player.")
    }

    override fun skipToPrevious() {
        println("Skipping to the previous video in the video player.")
    }
}

fun main() {
    // Creating instances of the AudioPlayer and VideoPlayer
    val audioPlayer = AudioPlayer()
    val videoPlayer = VideoPlayer()

    // Using the MediaPlayer interface to control both players
    audioPlayer.play()
    audioPlayer.skipToNext()
    audioPlayer.pause()

    videoPlayer.play()
    videoPlayer.skipToPrevious()
    videoPlayer.stop()
}

here is the output of this program

//Output
Audio player is playing.
Skipping to the next track in the audio player.
Audio player is paused.
Video player is playing.
Skipping to the previous video in the video player.
Video player is stopped.

In this example, the MediaPlayer interface declares common methods like play(), pause(), stop(), skipToNext(), and skipToPrevious(). The AudioPlayer and VideoPlayer classes then implement this interface, providing concrete implementations for each method.

In a media player application, using the MediaPlayer interface lets you control both AudioPlayer and VideoPlayer objects in a consistent way. This promotes code reuse and flexibility by ensuring a common set of functionalities for different types of media players.

Example of an interface That includes abstract methods, default methods, static methods, abstract properties, default properties, constants, and private methods:

interface ExampleInterface {

    // Abstract method
    fun abstractMethod(): String

    // Default method
    fun defaultMethod(): String {
        return "Default implementation of defaultMethod"
    }

    // Static method (companion object)
    companion object {
        // Constants
        const val CONSTANT_VALUE: String = "Constant value"

        fun staticMethod(): String {
            return "Static method implementation"
        }
    }

    // Abstract property
    val abstractProperty: String

    // Default property to provide defalt value
    val defaultProperty: String
        get() = "Default implementation of defaultProperty"



    // Private method
    private fun privateMethod(): String {
        return "Private method implementation"
    }

    // Public method that uses private method
    fun publicMethodUsingPrivate(): String {
        return privateMethod() + " in public method"
    }
}

// Example of a class implementing the interface
class ExampleClass : ExampleInterface {

    override val abstractProperty: String
        get() = "Implementation of abstractProperty"

    override fun abstractMethod(): String {
        return "Implementation of abstractMethod"
    }
}

fun main() {
    val exampleObj = ExampleClass()

    // Using methods and properties from the interface
    println(exampleObj.abstractMethod())
    println(exampleObj.defaultMethod())
    println(ExampleInterface.staticMethod())
    println(exampleObj.abstractProperty)
    println(exampleObj.defaultProperty)
    println(ExampleInterface.CONSTANT_VALUE)
    println(exampleObj.publicMethodUsingPrivate())
}

here is the output of this program

//Output
Implementation of abstractMethod
Default implementation of defaultMethod
Static method implementation
Implementation of abstractProperty
Default implementation of defaultProperty
Constant value
Private method implementation in public method

Let me explain the program

  • Static Method , Constants – This is a static method and constants defined in the companion object of the interface. It can be called using the interface name
  • Abstract Property (abstractProperty): This property is declared without an initial value. Classes implementing the interface must provide their own implementation for this property. Properties declared in interfaces are abstract by default.
  • Default Property (defaultProperty): This property has a default implementation in the interface. If a class implementing the interface doesn’t provide its own implementation, it will use this default implementation.
  • Private Method (privateMethod): This is a private method within the interface, and it can only be accessed within the interface itself.

Implementing multiple interfaces

In kotlin, a class can implement multiple interfaces by separating the interface names with commas. Here’s a simple example:

// Interface 1
interface Interface1 {
    fun method1()
}

// Interface 2
interface Interface2 {
    fun method2()
}

// Class implementing both interfaces
class MyClass : Interface1, Interface2 {
    override fun method1() {
        println("Method 1 implementation")
    }

    override fun method2() {
        println("Method 2 implementation")
    }
}

fun main() {
    val myObject = MyClass()
    myObject.method1()
    myObject.method2()
}
// Interface 1
interface Interface1 {
    fun method1()
}

// Interface 2
interface Interface2 {
    fun method2()
}

// Class implementing both interfaces
class MyClass : Interface1, Interface2 {
    override fun method1() {
        println("Method 1 implementation")
    }

    override fun method2() {
        println("Method 2 implementation")
    }
}

fun main() {
    val myObject = MyClass()
    myObject.method1()
    myObject.method2()
}
/*
 //Output
 Method 1 implementation
 Method 2 implementation
 * */

Keep in mind that if both interfaces declare a method with the same name, the implementing class must provide a concrete implementation for that method, resolving the potential conflict. Let’s consider an example where two interfaces declare a method with the same name:

// Interface 1
interface Interface1 {
    fun commonMethod()
}

// Interface 2
interface Interface2 {
    fun commonMethod()
}

// Class implementing both interfaces
class MyClass : Interface1, Interface2 {
    override fun commonMethod() {
        println("Concrete implementation of commonMethod")
    }
}

fun main() {
    val myObject = MyClass()
    myObject.commonMethod()
}
/*
 Output:
 Concrete implementation of commonMethod
 * */

Use cases of interfaces in Android

  1. Callback Mechanisms: Use interfaces for callbacks, allowing one component to notify another about events, like asynchronous task completion.
  2. Achieving Multiple Inheritance: In languages without direct multiple inheritance, interfaces help a class inherit from multiple sources.
  3. Enforcing Design Patterns: Observer and Factory Patterns: Interfaces are crucial for implementing Observer and Factory design patterns, defining contracts for object interaction and creation.
  4. Fragment Communication: Interfaces define communication contracts between fragments and their hosting activities, allowing decoupled interactions.
  5. Event Handling (e.g., Clicks): Interfaces define contracts for event handling, like item clicks in RecyclerViews, promoting consistency.
  6. Adapter Communication: Interfaces facilitate communication between adapters and hosting components, like handling item clicks in RecyclerViews.
  7. Dependency Injection: Interfaces provide contracts for dependency injection, promoting flexibility and testability in component interactions.
  8. Observer Pattern: Interfaces are key in implementing the Observer Pattern, where an object maintains a list of its dependents (observers) that are notified of state changes. The observers implement a common interface defining the update method.
  9. Retrofit Service: Interfaces define contracts for Retrofit services, specifying API endpoints and serving as blueprints for HTTP requests.


To learn more about Kotlin interfaces, check out the official documentation at: Kotlinlang

Leave a Reply