メンバーのオーバーライド
CoddyのKotlinジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 18/57。
サブクラスは、継承したメソッドを独自のバージョンに置き換えることができます。スーパークラスはメソッドに open を付け、サブクラスは override を付けてそのメソッドを再び宣言します。
open class Animal(val name: String) {
open fun sound() = "..."
}
class Dog(name: String) : Animal(name) {
override fun sound() = "Woof"
}
class Cat(name: String) : Animal(name) {
override fun sound() = "Meow"
}main の中では次のようにします。
println(Dog("Rex").sound())
println(Cat("Tom").sound())
println(Animal("Generic").sound())出力:
Woof
Meow
...実行されるバージョンは、変数の型がスーパークラスであっても、オブジェクトの実際のクラスによって選択されます。オープンメソッドを呼び出すスーパークラス内のコードも、サブクラスのバージョンを取得します。
open class Animal(val name: String) {
open fun sound() = "..."
fun speak() = "$name says ${sound()}"
}
class Dog(name: String) : Animal(name) {
override fun sound() = "Woof"
}mainの中では:
val pets: List<Animal> = listOf(Dog("Rex"), Animal("Generic"))
for (p in pets) println(p.speak())出力:
Rex says Woof
Generic says ...プロパティも同じ方法でオーバーライドできます。スーパークラスでは open val、サブクラスでは override val を使用し、通常のプロパティ、コンストラクタプロパティ、または計算ゲッターとして定義できます。
open class Shape {
open val name = "shape"
open val corners = 0
}
class Triangle : Shape() {
override val name = "triangle"
override val corners = 3
}
class Polygon(override val corners: Int) : Shape() {
override val name: String
get() = "$corners-gon"
}main 内では次のようにします。
for (s in listOf(Shape(), Triangle(), Polygon(6))) println("${s.name}: ${s.corners}")出力:
shape: 0
triangle: 3
6-gon: 6override としてマークされたメンバーは再びオープンになるため、サブクラスのサブクラスであればもう一度オーバーライドできます。final override はそれを停止します。open のないメンバーはまったくオーバーライドできず、サブクラスで同じシグネチャを持つメンバーを宣言することもできません。
open class Animal {
open fun sound() = "..."
fun sleep() = "zzz"
}
open class Dog : Animal() {
final override fun sound() = "Woof"
}
class Puppy : Dog() {
// override fun sound() = "Yip" // エラー: 'Dog' の 'sound' は final です
// fun sleep() = "nap" // エラー: 'sleep' はスーパークラスのメンバーを隠蔽します
}チャレンジ
簡単Animal には legs()(4)、sound()(...)、および describe() があり、legs() と sound() から構成された Rex has 4 legs and says Woof を返します。legs() と sound() をオーバーライド可能にし、その2つのメソッドだけをオーバーライドしてサブクラスを完成させてください。Dog は Woof と鳴き、Bird は脚が2本で Tweet と鳴き、Snake は脚が0本で Hiss と鳴きます。describe() は Animal にあるままにします。
提供されたコードは、dog,Rex、bird,Pip、snake,Kaa、またはその他の種類(通常の Animal)の行を読み取り、動物を1つの List<Animal> に格納し、それぞれに対して describe() を出力します。
コードは Animal.kt、Dog.kt、Bird.kt、Snake.kt に記述します。Main.kt には提供された入出力コードが含まれており、編集できません。
自分で試してみよう
fun main() {
// 提供された入出力コード: そのままにしておく
val input = generateSequence(::readLine).toList()
val animals = mutableListOf<Animal>()
for (line in input) {
val (kind, name) = line.split(",")
animals.add(when (kind) {
"dog" -> Dog(name)
"bird" -> Bird(name)
"snake" -> Snake(name)
else -> Animal(name)
})
}
for (a in animals) println(a.describe())
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Kotlinプレイグラウンド