覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

Kotlin - インターフェース

Java で インターフェースの定義をするコードは以下のようになります。

public interface Printable {

    void print();

    void printDetail();
}

そしてこのインターフェースを実装した実装クラスのコードは以下のようになります

public class JavaPrinter implements Printable {

    @Override
    public void print() {
        System.out.println("Java summary");
    }

    @Override
    public void printDetail() {
        System.out.println("Java detail print");
    }
}

実装するインターフェースを指定する部分で implements キーワードを記述します。

以下コードで実行してみると

Printable printer = new JavaPrinter();

printer.print();
printer.printDetail();

結果は以下の通りです。当然の結果ですが。

Java summary
Java detail print


ちなみに先ほどの実装クラスのJavaPrinterは以下のように書く事もでき、@Override アノテーションの記述なしでもコンパイルが通ります。

public class JavaPrinter implements Printable {

    public void print() {
        System.out.println("Java summary");
    }

    public void printDetail() {
        System.out.println("Java detail print");
    }
}


Kotlinのインターフェース

KotlinとJavaは相互に呼び出し可能であることから、先ほどJavaで書いた Printable インターフェースを Kotlinのクラスとして実装可能です。

以下のようになります

class KotlinPrinter : Printable {
    override fun print() {
        println("Kotlin summay")
    }

    override fun printDetail() {
        println("Kotlin detail print")
    }
}

Kotlin ではクラス名の後ろに implements キーワードの代わりに : (コロン)を記述して、そのあとにインターフェース名を指定します。
ちなみに、Java では継承の場合は extends キーワードを使いますが、Kotlinの場合は継承の場合でも : (コロン)を使います。

以下は先ほどの Kotlin での実装クラスを実行するコードです

val printer : Printable = KotlinPrinter()
printer.print()
printer.printDetail()

実行結果は以下の通りです。

Kotlin summay
Kotlin detail print


ちなみに実装クラスを以下のようにしようとするとコンパイルエラーとなります。

// コンパイルエラー
class KotlinPrinter : Printable {
    fun print() {
        println("Kotlin summay")
    }

    fun printDetail() {
        println("Kotlin detail print")
    }
}

これは、override 修飾子 がないためです。
Kotlin の override 修飾子 は、Java の@Override アノテーションと同様に、スーパークラスやインターフェースをオーバライドするメソッドやプロパティを指定するために利用します。
しかし、Javaとは違って Kotlin の override 修飾子は省略できません。必須です。


Javaでのインターフェースしか書いていませんでしたが、Kotlinでのインターフェースの記述は以下のようになります。

interface Printable {

    fun print()

    fun printDetail()
}

ちなみに、インターフェースはデフォルトの実装を持つ事ができます。
Java 8とは異なって、Kotlinではメソッドに default というような特別なキーワードをつける必要はありません。

デフォルト実装をも持たせたインターフェースの例は以下の通りです。
デフォルト実装を持つメソッドを実装クラス側でオーバーライドしなければ、インターフェースに定義したデフォルトの処理が実行されます。

interface Printable {

    fun print() = println("Hello World")

    fun printDetail()
}


さらにここに以下のようなインターフェースを登場させて

interface Display {
    fun print() = println("Hello Display")
}

KotlinPrinterクラスに両方のインターフェースを実装させて、デフォルト実装をオーバーライドしないようにしようとするとコンパイルエラーとなります。

// コンパイルエラー
class KotlinPrint : Printable, Display {

    override fun printDetail() {
        println("Detail Print")
    }
}

複数のインターフェースから、複数の実装を継承してしまっているためです。
このようなケースでは、以下のように実装クラスで必ず対象のメソッドをオーバーライドする必要があります。

class KotlinPrint : Printable, Display {
    
    override fun print() {
        super<Printable>.print()
        super<Display>.print()
    }

    override fun printDetail() {
        println("Detail Print")
    }
}

ここで super<Printable>.print()super<Display>.print() の部分が継承したデフォルト実装を呼び出すコードになっています。
super.<親の型名>.{メソッド名} の記述が、継承元のメソッドを呼び出すことになります。


まとめ

Kotlin での インターフェースの定義方法と実装方法の基礎が分かりました。
まだ、この辺りだとJavaとの大きな違いは無いかなという印象です。