14日目:継承とオーバライドの約束
Kotlinにも継承の仕組みが備わっています。継承により、上位のクラス(スーパクラス)の型のサブセットとなることができ、さらにスーパクラスの実装を受け継ぐことになります。再利用性を高める重要な機能について今日は見ていきます。
継承
継承は、上位のクラスを基に、派生したクラス(サブクラス)を簡単に作成する機能です。Kotlinの継承は、Javaのそれと同じです。が、ところどころコード記述や細かいルールが異なります。
基本は継承できない
Kotlinではクラスを定義した際、デフォルトで継承を禁止しています。Javaで言うところのfinalクラスです。この慎重な設計思想はEffective Java 第2版の項目17*1に基づいています。そのため、継承を許可するクラスを作成するには、クラスにアノテーション openを付けて定義します。
open class SuperClass(val name : String)
継承する
では次に、上記のクラス SuperClass を継承したクラス SubClass を定義しましょう。やり方は簡単です。クラス定義の際、自身のプライマリ・コンストラクタに続けて、コロンとスーパクラスの名前とプライマリ・コンストラクタを記述します。
class SubClass(name : String) : SuperClass(name)
スーパクラスのプライマリ・コンストラクタにはパラメータをセットする必要があります。上記の例では、サブクラスのプライマリ・コンストラクタで受け取った値をスーパクラスのプライマリ・コンストラクタに転送しています。
オーバライド
継承により、スーパクラスの持っているインスタンス関数はサブクラスにコピーされますが、その関数をサブクラス側で上書きして実装を変更することをオーバライドと言います。オーバライドもJavaよりも厳しいルールとなっています。
open class SuperClass(val name : String) { open fun printName() { println("$name") } } class SubClass(name : String) : SuperClass(name) { override fun printName() { println("!!! $name !!!") } }
その他、細かいルールがあります。
- open指定していないクラスの関数にはアノテーション openを付けられない(関数をopenにしたところで意味がないから)
- オーバライドした関数にアノテーション openを付けられない(既にopen状態であるから)
- オーバライドした関数の再オーバライドを許可したくない場合はアノテーション finalを付ける
まとめと次回予告
今日はKotlinにおける継承について勉強しました。Javaと同様にクラスは、他のクラスを継承することができます。また、スーパクラスが持つ関数をオーバライドすることができます。ただし、継承やオーバライドをするための制限がJavaよりも厳しいです。それは足枷ではなく、不注意な設計判断によってクラスのカプセル化が損なわれてしまう事態を回避する工夫です。
明日はトレイトと呼ばれるJavaで言うインタフェースのようなものの紹介をします。また、それに関連して、オーバライドのルールをもう少しだけ紹介します。トレイトを利用した委譲パターンの簡単な実装法についてもお話しします。
日記
Scala勉強中。面白いけどやっぱり複雑という印象。
*1:項目17 「継承のために設計および文書化する、でなければ継承を禁止する」