Interfaces
The interface keyword defines a new interface. Within the interface body you list methods that class must implement. An empty interface is allowed.
Kotlin supports methods with default implementation. Such methods are called non-abstract and can be private.
The override keyword allows you to override a method in an inherited interface or in a class that implements the interface.
An overridden method can change the return type to any subclass.
A class can implement multiple interfaces. A non-abstract class must implement all methods of the specified interfaces.
// an empty interface
interface Empty
interface InterfaceName {
fun foo()
fun bar(arg: Int=56): Boolean
fun printBar(arg: Int){println("bar is ${bar(arg)}")}
fun newObj(): ClsA
}
interface InterfaceName2: InterfaceName, Empty {
override fun newObj(): SubClsA
}
class Cls : InterfaceName, Empty{
override fun foo(){ ... }
override fun bar(arg: Int) = arg%2 == 0
// this class uses default implementation of printBar
}
default implementation
You can override the () operator of companion object to provide default implementation.
interface Demo {
fun foo()
companion object {
operator fun invoke(): Demo = DemoImpl()
}
}
class DemoImpl : Demo {
override fun foo() {
// ...
}
}
// usage: val demo = Demo()
anonymous instance
An anonymous instance of an interface can be created through an anonymous object.
interface Task {
fun onTask(workerActions: WorkerActions)
}
var mainTask = object : Task{
override fun onTask( workerActions: workerActions) {
TODO("Not yet implemented")
}
}
functional interface
You can declare a single abstract method (SAM) interface as a functional interface with the fun keyword. This allows you to convert the interface to a lambda function and vice versa.
val task = Runnable {
// do stuff
}
fun interface Task {
fun onTask(workerActions: WorkerActions)
}
class Worker{
...
// methods accept interface
open fun onPreProcess(task: Task): Worker{...}
open fun onPostProcess(task: Task): Worker{...}
open fun onMainTask(task: Task): Worker{...}
}
// but we can use lambdas, instead anonymous implementation
val worker = Worker().onMainTask{ actions->
...
}.onPreProcess{ actions->
...
}.onPostProcess{ actions->
...
}
properties
You can add properties to the interface. This will be considered a shorthand for getter/setter methods. These properties cannot be initialized.
interface TaskData<T> {
val data: T?
}
class MutableTaskData<T> : TaskData<T> {
override var data: T? = null
}
interface ProgressDataInfo {
val current: Long
val total: Long
}
class ProgressData : ProgressDataInfo {
var mCurrent: Long = 0
var mTotal: Long = 0
override val current: Long
get() = mCurrent
override val total: Long
get() = mTotal
}
delegation
A class can delegate the implementation of an interface to another object.
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).print()
}
resolving overriding conflicts
When we declare many types in our supertype list, it may appear that we inherit more than one implementation of the same method.
interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar() { print("bar") }
}
class D : A, B {
override fun foo() {
super<A>.foo() // call A implementation
super<B>.foo() // call B implementation
}
override fun bar() {
super<B>.bar() // call B implementation
}
}