こんにちは!リンコですピヨ!この記事では自分の勉強の復習もかねて、Kotlinでのクラスの継承とオーバーライドについて解説するピヨ!
この第21章では、プログラミング言語であるKotlinのクラスの継承とオーバーライドについて、一緒に勉強していきましょう。
この記事を読めばプログラミング未経験の方も、Kotlin入門レベルのクラスの継承とオーバーライドについて1つ1つ理解しながら勉強できると思うので、是非最後まで読んで頂ければと思います。
※この記事で出てくる「サンプルコード」は、記述が長く画面からはみ出ている場合がありますが、横にスライドすると表示されるのでご安心ください。
【Kotlin】継承とは?
ではまず、継承というのはどんな処理のことを言うのでしょうか?継承について勉強していきましょう。
既存のクラスをベースにすること
継承は既存のクラスをベースにして、少し手を加えて新しいクラスに作り変えることを言います。
Kotlinでは他人が作った設計図に手を加えるためだけではなく、自分が作ったクラスを自分自身で再利用するためにも使用できます。
エクセル等で同じような資料を作成する際に、テンプレートを用意しコピペして手を加えるような感じに似ています。
労力の削減になる
同じようなコードを記述するために毎回ゼロから記述すると、かなりの労力がかかってしまいます。
ですが継承の機能を使ってある程度体裁が整ったテンプレをコピーして、それをベースに修正していく方が時間も短縮されますし、ミスも少なくなります。
コードの見た目が統一される
各コードに記述されている細かな内容はそれぞれ違いますが、コードの見た目が一緒の方が統一感が出て見やすくなります。
既存のクラスを元に、新しいクラスを作り書き換えることを継承と言うピヨ!
【Kotlin】クラスを継承してみよう
続いて、実際にクラスの継承の記述の仕方を勉強していきましょう。
クラスの継承の書式
クラスの継承の書式は、以下のようになります。
open class クラス名() { open fun 関数名() { 処理内容 } } class 継承クラス名() : 基底クラス名()
※ベースになる既存のクラスのことを「基底クラス」と言います
「open」をつける
クラスの最初に書いてある「open」は、このクラスが「継承可能」であることを示しています。
クラス定義の先頭にopenと付け加えることによって、このクラスが継承可能で「テンプレート」として使うことができるようになります。
Kotlinでは、このopenというキーワードがついていないクラスは、他のクラスから継承できないので注意しましょう。
「:基底クラス名()」で継承できる
継承するクラスの記述側で「class 継承クラス名() : 基底クラス名()」のように「:基底クラス名()」と記述することで、継承クラスが基底クラスをベースにしたものであることを表します。
「open」の反対語で「final」もある
finalというキーワードをクラスの最初に記述すると、他のクラスの継承元として使うことができなくなります。
ただし、Kotlinではopenなしにクラスを定義すると、全てデフォルトでfinal扱いになっているので、わざわざfinalと記述する必要はありません。
基底クラスの先頭に「open」をつけることで継承が可能になるピヨ!
まずはテンプレとなるクラスを作ってみよう
クラスの継承の書式がわかったところで、まずはテンプレとなるクラスを先に作ってみましょう。
サンプルコード
以下がクラスのテンプレとなるサンプルコードになります。
fun main() { val bird = Bird() bird.fly(5.0) // 鳥を5キロ飛ばせる bird.fly(10.0) // 鳥を10キロ飛ばせる } open class Bird() { var distance = 0.0 open fun fly(d: Double) { distance = distance + d println("鳥が${d}km飛びました。") println("とんだ距離の合計が${distance}キロになりました。") } }
こんな感じで、Birdという鳥の基底クラスを作りました。クラスと関数の先頭に「open」と記述がありますね。
この基底クラスでは、飛行距離を表すdistanceというプロパティ変数が1つと、鳥を飛ばせるflyという関数が定義されています。
この関数flyは、鳥が飛ぶ距離をパラメータとして受け取るようになっていて、関数flyが呼ばれるとプロパティ変数distanceに、パラメータとして指定されたdの値にプラスされます。
またdistanceというプロパティの値が、飛行距離の合計を表しています。
出力
サンプルコードを実行すると、以下のように出力されます。
鳥が5.0km飛びました。 とんだ距離の合計が5.0キロになりました。 鳥が10.0km飛びました。 とんだ距離の合計が15.0キロになりました。
実際にクラスの継承をしてみよう
では実際に、クラスの継承を行ってみましょう。
サンプルコード
以下のサンプルコードでは、鳥のクラスを継承して「リンコ」を表すクラスを設計します。
fun main() { val rinko = Rinko() // リンコをインスタンス化 rinko.fly(5.0) rinko.fly(10.0) } open class Bird() { var distance = 0.0 open fun fly(d: Double) { distance = distance + d println("鳥が${d}km飛びました。") println("とんだ距離の合計が${distance}キロになりました。") } } class Rinko () : Bird()
上記のように記述するとRinkoクラスはBirdクラスが持っている機能をすべて引き継ぐようになります。
コードの右側「:Bird()」という記述はBirdクラスのコンストラクタを表しており、これを記述することによりRinkoクラスがBirdクラスをベースにしたものであることを表しています。
この場合「RinkoクラスはBirdクラスを継承している」または「BirdクラスはRinkoクラスの基底クラス」という言い方になります。
出力
サンプルコードを実行すると、以下のように出力されます。
鳥が5.0km飛びました。 とんだ距離の合計が5.0キロになりました。 鳥が10.0km飛びました。 とんだ距離の合計が15.0キロになりました。
この例では上記のように先程と全く同じ出力結果で、RinkoクラスとBirdクラスは実質的に全く同じものということになりますが、たった1行だけでクラスの実装ができているということがわかりました。
クラスの継承はよく使うので、継承の記述は覚えておくピヨ!
【Kotlin】クラスの継承でプライマリコンストラクタを実装してみよう
ここまででは、コンストラクタを記述していませんでしたが、ここからはパラメータ付きのコンストラクタの実装をして、より意味のあるコードにしていきます。
サンプルコード
このサンプルコードでは、鳥の体の色を実装していきます。
fun main() { val rinko = Rinko("黄色") // リンコをインスタンス化 rinko.fly(5.0) rinko.fly(10.0) } open class Bird(val color: String) { var distance = 0.0 open fun fly(d: Double) { distance = distance + d println("鳥が${d}km飛びました。") println("飛んだ距離の合計が${distance}キロになりました。") } } class Rinko (color: String) : Bird(color)
出力
サンプルコードを実行すると、以下のように出力されます。
鳥が5.0km飛びました。 飛んだ距離の合計が5.0キロになりました。 鳥が10.0km飛びました。 飛んだ距離の合計が15.0キロになりました。
上記のBirdクラスの定義では、プライマリコンストラクタへ渡すパラメータを「val color: String」と定義していて、この記述はプロパティ変数の定義も兼ね備えています。
基底クラスのBirdクラスにプライマリコンストラクタを実装したことで、それを継承したRinkoクラスの定義も変更する必要があり、「class Rinko (color: String) : Bird(color)」とコードを記述し、RinkoクラスもプライマリコンストラクタでcolorというString型の変数を受け取るようになっています。
そしてその変数は基底クラスのBirdクラスのコンストラクタにそのまま「スルーパス」されているイメージになります。
ただし、このままでは基底クラスも継承したクラスも全く同じですし、鳥の体の色も実装されません。2つのクラスで違いを出すためには、オーバーライドを勉強する必要があります。
それを以下から勉強していきましょう。
サンプルコードを、より意味のあるものにしていくピヨ!
【Kotlin】オーバーライドとは?
では続いて、オーバーライドについて勉強していきましょう。まずは、オーバーライドが何なのかを見ていきます。
継承したクラスの関数を書き換えること
オーバーライドは、継承したクラスの関数を書き換えられるようにし、基底クラスと継承したクラスに違いを出せることを言います。
この記事のサンプルコードで言うと、BirdクラスとRinkoクラスに違いを出すためのものですね。
「〇〇関数がオーバーライドされた」と表現する
コードにオーバーライドを実装すると「〇〇関数がオーバーライドされた」と表現します。
以下で実際に実装していきますが、この記事のサンプルコードで言うと「fly関数がオーバーライドされた」ということになります。
【Kotlin】オーバーライドを実装してみよう
では実際に、オーバーライドを実装してみましょう。
オーバーライドの書式
まずオーバーライドを実装するための書式は、以下のようになります。
class クラス名 (プロパティ名: 型名) : 基底クラス名(プロパティ名) { override fun 関数名(変数名: 型名) { 独自機能の内容 } }
継承先に定義ブロックを追加する
まず継承先のクラスに独自機能を付け加える場所を用意するために「定義ブロック」を準備します。
定義ブロックは「{}」を使います。「{}」内にコードを記述することで、独自機能を付け加えることができます。
継承先では「override」をつける
継承したクラスの関数を独自のものに置き換えたい場合は、関数定義の先頭に「override」という文言をつける必要があります。
Birdクラスのfly関数の先頭に「open」という文言をつけていましたが、基底クラスでopenがついている関数はそれを継承したクラスでも書き換えが可能なものとして「公開」されていることになります。
そして継承した側のクラスの関数でoverrideをつけることによって、基底クラスに存在している同名の関数を「上書き」することができるようになります。
継承先のクラスの関数の先頭に「override」をつけることで独自の関数に書き換えられるピヨ!
実際にオーバーライドを実装してみよう
では最後に、実際にオーバーライドを実装してみましょう。
サンプルコード
以下のサンプルコードでは、基底クラスのBirdクラスと継承先のクラスのRinkoクラスを、それぞれインスタンス化して実行しています。
基底クラスのBirdクラスは今までのコードと同じですが、継承先のクラスのRinkoクラスでは、今までとは少し変えて違いを出しているので、そこに注目してみてください。
fun main() { val bird = Bird("")// 鳥をインスタンス化 bird.fly(5.0) // 鳥を5キロ飛ばせる bird.fly(10.0) // 鳥を10キロ飛ばせる val rinko = Rinko("黄色") // 「リンコ」をインスタンス化 rinko.fly(10.0) // 「リンコ」を10キロ飛ばせる } open class Bird(val color: String) { var distance = 0.0 open fun fly(d: Double) { distance = distance + d println("鳥が${d}km飛びました。") println("飛んだ距離の合計が${distance}キロになりました。") } } class Rinko (color: String) : Bird(color) { override fun fly(d: Double) { distance = distance + d println("${color}のリンコが飛んでる!パタパタ!") println("飛んだ距離は${distance}です。") } }
出力
サンプルコードを実行すると、以下のように出力されます。
鳥が5.0km飛びました。 飛んだ距離の合計が5.0キロになりました。 鳥が10.0km飛びました。 飛んだ距離の合計が15.0キロになりました。 黄色のリンコが飛んでる!パタパタ! 飛んだ距離は10.0です。
最初に出力された「鳥」の部分は今までと同じですね。
その後ですが「override」を継承した先のクラスの関数の先頭に記述すると、基底クラスの同名の関数の動作を書き換えることができます。
もちろん継承した側のクラスでは、継承元の基底クラスには存在しない関数やプロパティを新たに追加してもOKです。
このようにオブジェクト指向のプログラムでは、基底クラスの既存の関数やプロパティを書き換えたり、新規に追加することが多くなりますので、クラスの継承やオーバーライドはしっかり覚えておきましょう。
特にアンドロイドなどのフレームワークではこの考え方を多用するのでしっかり覚えておくピヨ!
まとめ
この記事では、プログラミング言語であるKotlinのクラスの継承とオーバーライドについて勉強していきましたが、いかがでしたでしょうか?今回の記事をまとめると以下のようになります。
- 継承は既存のクラスを元に、新しいクラスを作り書き換えること
- ベースとなるクラスを基底クラスという
- 基底クラスの先頭に「open」と付けることで「継承可能」を意味する
- 継承先のクラスの関数の先頭に「override」をつけると関数を上書きできる
- オーバーライドしたい時には基底クラスの関数の先頭に「open」をつける
今回勉強した「クラスの継承」や「オーバーライド」はKotlinの入門レベルの知識になるので、何回も読み直してしっかり覚えておきましょう。
次回の記事では「オーバーロードとポリモーフィズム」について勉強していくピヨ!
プログラミング未経験の方や入門レベルの方、Kotlinについて詳しくなりたい方は、また一緒に勉強するピヨ!
コメント