インターフェース
Kotlinでのインタフェースは、抽象メソッドの宣言と、さらにメソッドの実装も含めることができます。 抽象クラスと違う所は、インタフェースは状態を持てません。 インタフェースはプロパティを持つことができますが、これらは abstract であること、またはアクセサの実装を提供することが必要です。
インタフェースは、 interface キーワードを使用して定義されます。
interface MyInterface {
fun bar()
fun foo() {
// 本体(body)をつけてもいい
}
}
インタフェースの実装
クラスやオブジェクトは、1つまたは複数のインターフェイスを実装することができます:
class Child : MyInterface {
override fun bar() {
// 本体
}
}
インターフェイス内のプロパティ
インターフェイス内にプロパティを宣言することができます。 インタフェースで宣言されたプロパティは、 abstract にするか、アクセサの実装を提供するかしなくてはいけません。 インタフェース内で宣言されたプロパティはバッキングフィールドを持つことはできず、それ故にインタフェース内で宣言されたアクセサはそれらを参照できません。
interface MyInterface {
val prop: Int // abstract
val propertyWithImplementation: String
get() = "foo"
fun foo() {
print(prop)
}
}
class Child : MyInterface {
override val prop: Int = 29
}
インターフェースの継承
インターフェースは他のインターフェースを継承する事が出来ます。 それが意味する所は、 継承元のメンバを継承先のインターフェースが実装して提供したり、 さらに追加で新たな関数やプロパティを宣言出来たりもするという事です。 自然な帰結として、 そのようなインターフェースを実装するクラスは、 実装がまだ提供されていないものだけを実装すれば良くなります。
interface Named {
val name: String
}
interface Person : Named {
val firstName: String
val lastName: String
override val name: String get() = "$firstName $lastName"
}
data class Employee(
// 'name'の実装は必要では無い
override val firstName: String,
override val lastName: String,
val position: Position
) : Person
オーバーライドの競合解決
スーパータイプのリストでたくさんの型を宣言すると、同メソッドの複数の実装を継承するように見えることがあります。例えば:
interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar() { print("bar") }
}
class C : A {
override fun bar() { print("bar") }
}
class D : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar() {
super<B>.bar()
}
}
インタフェース A と B は、両方とも関数 foo() と bar() を宣言しています。両方とも foo() を実装していますが、 B のみが bar() を実装しています。( bar() は A では abstract としてマークされていません。abstractなのはインタフェースで関数が本体を持たないときのデフォルトだからです。) さて、もし具象クラス C を A から継承すれば、 bar() をオーバライドし、実装を提供しなければならないことは明らかです。
しかしながら、もし D を A と B から継承すれば、 複数のインターフェースから継承した全メソッドを実装する必要があり、 つまりDでもそれらを実装する必要があります。 このルールは一つの実装だけを継承しているもの(bar())にも、 複数の実装を継承しているもの(foo())にも、どちらにも適用されます。