ザクっと理解するKotlin Interface
Kotlinでは、インターフェースを使うことで、プログラムの柔軟性や再利用性を高めることができます。
本記事では、Kotlinのインターフェースについて、基礎から実装まで詳しく解説します。
プロパティや関数、実装時の重複解決方法まで、実践的なサンプルコードを交えながら紹介します。
より効率的な開発を行う助けになればと思います。
インターフェースとは
クラスが最低限実装しなければならないプロパティや関数を定義するものです。
もっと簡単に言うと、クラスに対する最低限の守らなければならないルールを設定するものです。
コード例とともに見ていきたいと思います。
interface Interface01 {
var property01: String
abstract var property02: Int
val property03: String
get() = "property03"
fun function01()
fun function02()
fun function03() {
println("Interface01 function03")
}
abstract fun function04()
}
このコードではInterface01という名前のインターフェースを設定しています。
インターフェースにはproperty01、property02、property03プロパティとfunction01、function02、function03、function04関数が設定されています。
インターフェースのプロパティ
インターフェースのプロパティは抽象プロパティとして宣言する、もしくはアクセッサーを設定することができます。
しかしインターフェースで宣言されたプロパティはバッキングフィールドを持ちません。
そのためバッキングフィールドの使用はできません。
interface Animal {
var property01: String
abstract var property02: Int
val property03: String
get() = "property03"
...
}
インターフェース内のアクセッサーを持たないプロパティは抽象プロパティであるため、property01とproperty02は両方とも抽象プロパティです。
一方、property03はアクセッサーを設定しています。
インターフェースのアクセッサーではバッキングフィールドを使用できないため、デフォルト値を返しています。
インターフェースの関数
interface Interface01 {
...
fun function01()
fun function02()
fun function03() {
println("Interface01 function03")
}
abstract fun function04()
}
インターフェースの関数はデフォルトで抽象関数になります。
そのためfunction01、02、04は抽象関数です。
しかしfunction03はボディを持っているため、オーバーライド可能な関数(open function)となります。
インターフェースの実装
class Class01: Interface01 {
override var property01 = "property01"
override var property02 = "property02"
var property04 = "property04"
override fun function01() {
println("Interface01 function01")
}
override fun function02() {
println("Interface01 function02")
}
override fun function04() {
println("Interface01 function04")
}
fun function05() {
println("Class01 function05")
}
}
interface Interface01 {
var property01: String
abstract var property02: String
val property03: String
get() = "property03"
fun function01()
fun function02()
fun function03() {
println("Interface01 function03")
}
abstract fun function04()
}
Class01はInterface01を実装しています。
Class01でproperty01、02をオーバーライドし、新しいプロパティproperty04を宣言しています。
また、function01、02、04をオーバーライドし、新しい関数function05を宣言しています。
このようにインターフェースを実装する際は、プロパティや関数として未完成のもののみを実装するだけで問題ありません。
実装内容の重複
重複するメンバー(プロパティや関数)を持つ複数のインターフェースを実装する場合は、オーバーライドする必要があります。
まずは下記のコードをご覧ください。
class Class01: Interface01, Interface02 {
fun function02() {
println("Class01 function02")
}
}
interface Interface01 {
val property01: String
get() = "Interface01 property01"
fun function01() {
println("Interface01 function01")
}
}
interface Interface02 {
val property01: String
get() = "Interface02 property01"
fun function01() {
println("Interface02 function01")
}
}
この2つのインターフェースは全く同じ名前のプロパティと関数をそれぞれに持っています。
そしてクラスは両方を実装しています。
この場合、下記のように実行しようとすると
fun main() {
val class01 = Class01()
println(class01.property01)
class01.function01()
}
Class ‘Class01’ must override public open val property01: String defined in Interface01 because it inherits multiple interface methods of it
訳: 複数のインターフェースから同じ名前のプロパティを実装しているため、Class01クラスはInterface01で宣言されているproperty01をオーバーライドする必要があります。
とエラーが表示されます。
また関数に関しても同様のエラーが表示されます。
これを避けるためにはオーバーライドする必要があります。
しかしオーバーライドして、対象のインターフェースのボディを再度書く必要はありません。
super<インターフェース名>.関数名でインターフェースの関数を呼び出せます。
class Class01: Interface01, Interface02 {
override val property01 = super<Interface01>.property01
override fun function01() {
super<Interface01>.function01()
}
}
想定されるエラー
must override public open val プロパティ名
Class ‘クラス名’ must override public open val プロパティ名: 型名 defined in インターフェース名 because it inherits multiple interface methods of it
訳: 複数のインターフェースから同じ名前のプロパティを実装しているため、クラスはインターフェースで宣言されているプロパティをオーバーライドする必要があります。
原因
実装している複数のインターフェースに同じ名前のプロパティがあるため
解決方法
上記エラーで指摘されているプロパティをクラスでオーバーライドする
must override public open fun 関数名
Class ‘クラス名’ must override public open fun 関数名: 型名 defined in インターフェース名 because it inherits multiple interface methods of it
訳: 複数のインターフェースから同じ名前の関数を実装しているため、クラスはインターフェースで宣言されている関数をオーバーライドする必要があります。
原因
実装している複数のインターフェースに同じ名前の関数があるため
解決方法
上記エラーで指摘されているをクラスでオーバーライドする
Property initializers are not allowed in interfaces
Property initializers are not allowed in interfaces
訳: インターフェースでのプロパティの初期化はできません
原因
インターフェースでプロパティの初期化を試みているため
解決方法
抽象プロパティで宣言し、実装しているクラスでオーバーライドするかデフォルト値を代入する
not abstract and does not implement abstract member
Class ‘クラス名’ is not abstract and does not implement abstract member public abstract fun 関数名: 型名 defined in インターフェース名
訳: インターフェースを実装しているクラスが抽象クラスでないにも関わらず、インターフェースで定義されている抽象関数を実装していません
原因
インターフェースの抽象関数をクラスで実装し忘れている
解決方法
cannot have a backing field
Property in an interface cannot have a backing field
訳: インターフェースのプロパティはバッキングフィールドを持っていません
原因
インターフェースのプロパティでバッキングフィールドを使おうとしている
解決方法
抽象プロパティとして宣言し、クラスで実装するかデフォルト値を返す
コメント