Kotlin Interfaces
Interfaces
Like abstract classes, interfaces cannot be instantiated directly. They define properties and methods that must be implemented. If an abstract class is mainly for “inheritance”, an interface defines the “capabilities” of a subclass, and a single subclass can implement multiple interfaces.
Kotlin interfaces can contain abstract methods and method implementations. The difference from abstract classes is that interfaces cannot store property state.
In other words, properties in an interface cannot have initializers.
interface User {
val name = "devkuma" // Error: property initializers are not allowed in interfaces.
}
Interfaces are defined with the interface keyword.
interface MyInterface {
fun bar()
fun foo() {
// optional body
}
}
Implementing Interfaces
A class or object can implement one or more interfaces. When it inherits an interface, it must implement the interface members.
class Child : MyInterface {
override fun bar() {
// body
}
}
Properties in Interfaces
Properties can be declared in interfaces. A property declared in an interface must either be abstract or provide an accessor implementation. Because properties cannot be initialized in interfaces, accessors declared in interfaces cannot refer to backing state.
interface MyInterface {
val prop: Int // abstract
val propertyWithImplementation: String
get() = "foo"
fun foo() {
print(prop)
}
}
class Child : MyInterface {
override val prop: Int = 29
}
Interfaces Inheritance
Interfaces can inherit from other interfaces. Therefore, an inheriting interface can implement members from the parent interface or declare new methods and properties.
A class that implements such an interface only needs to implement the members that remain unimplemented.
interface Named {
val name: String
}
interface Person : Named {
val firstName: String
val lastName: String
override val name: String get() = "$firstName $lastName"
}
data class Employee(
// implementing 'name' is not required
override val firstName: String,
override val lastName: String,
val position: Position
) : Person
If the name: String property from the Named interface had not been implemented in Person, it would need to be implemented in Employee.
Resolving overriding conflicts
When implementing multiple interfaces, the same methods may be inherited from more than one interface.
interface A {
fun foo() { println("A") }
fun bar() // abstract
}
interface B {
fun foo() { println("B") }
fun bar() { println("bar") }
}
class C : A {
override fun bar() { println("bar") }
}
class D : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar() {
super<B>.bar()
}
}
fun main() {
val c = C()
c.foo()
c.bar()
println()
val d = D()
d.foo()
d.bar()
}
Interfaces A and B both declare the foo() and bar() functions. Both A and B implement foo(). A does not implement bar(), but B does.
Class C inherits only from interface A, so it only needs to implement bar().
Class D inherits from interfaces A and B, so it needs to explicitly handle the duplicated methods. This applies both to the bar() function, which has only one implementation, and the foo() function, which has multiple implementations.