Menu
Coddy logo textTech

superとコンストラクタ

CoddyのKotlinジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 19/57。

super.method()は、オーバーライドしたメソッドの内部からスーパークラス版のメソッドを呼び出します。サブクラスは、継承した動作を置き換えるのではなく拡張できます。

open class Notification(val text: String) {
    open fun render() = "[info] $text"
}
class Reminder(text: String, val minutes: Int) : Notification(text) {
    override fun render() = super.render() + " (in $minutes min)"
}

mainの内部では次のようにします。

println(Notification("backup done").render())
println(Reminder("meeting", 10).render())

出力:

[info] backup done
[info] meeting (in 10 min)

すべてのサブクラスは、スーパークラスのコンストラクターを呼び出す必要があります。プライマリコンストラクターでは、呼び出しはヘッダーの一部である : Base(arguments) となり、引数はサブクラスのパラメーターから計算できます。

open class Product(val name: String, val price: Int)

class Discounted(name: String, price: Int, val percent: Int) :
    Product(name, price * (100 - percent) / 100)

main の内部では:

val tea = Discounted("tea", 500, 10)
println("${tea.name} ${tea.price} (${tea.percent}% off)")

出力:

tea 450 (10% off)

生成は階層の上から下へ進みます。スーパークラスのプロパティ初期化子とinitブロックが最初に実行され、次にサブクラスのものが実行されます。

open class Base(name: String) {
    init { println("Base init for $name") }
}
class Child(name: String) : Base(name.uppercase()) {
    init { println("Child init for $name") }
}

mainの内部:

Child("kit")

出力:

Base init for KIT
Child init for kit

プライマリコンストラクターを持たないクラスは、各セカンダリコンストラクターから super(...) を使ってスーパークラスを呼び出すか、this(...) を使って自身の別のコンストラクターに委譲します:

open class Shape(val name: String)

class Rect : Shape {
    val w: Int
    val h: Int

    constructor(w: Int, h: Int) : super("rect") {
        this.w = w
        this.h = h
    }

    constructor(side: Int) : this(side, side)
}

main の中で:

val r = Rect(3)
println("${r.name} ${r.w}x${r.h}")

出力:

rect 3x3

スーパークラスは先に初期化されるため、そのコンストラクターや init から open メンバーを呼び出してはいけません。サブクラス自身のプロパティに値が設定される前に、オーバーライドされたメソッドが実行されます。

open class Base {
    init { println("Base sees: ${describe()}") }
    open fun describe() = "base"
}
class Child : Base() {
    val label = "child"
    override fun describe() = "label is $label"
}

main の内部で:

Child()

出力:

Base sees: label is null
challenge icon

チャレンジ

簡単

Notification(text) には、[info] text を返す open メソッド render() があります。サブクラスを完成させてください。Warning の render() は、テキストを大文字にして [warn] TEXT を返し、minutes も保存する Reminder は、super を使ってスーパークラスの結果の後に (in 10 min) を続けて返します。

提供されたコードは、info,text、warn,text、または remind,text,10 の行を読み取り、1つの List<Notification> に対応するオブジェクトを作成し、それぞれに対して render() を出力します。

コードは Notification.kt、Warning.kt、Reminder.kt に記述します。Main.kt には提供された入力/出力コードが含まれており、編集できません。

自分で試してみよう

fun main() {
    // 提供された入出力コード: そのままにしておく
    val input = generateSequence(::readLine).toList()
    val notes = mutableListOf<Notification>()
    for (line in input) {
        val p = line.split(",")
        notes.add(when (p[0]) {
            "warn" -> Warning(p[1])
            "remind" -> Reminder(p[1], p[2].toInt())
            else -> Notification(p[1])
        })
    }
    for (n in notes) println(n.render())
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Kotlinプレイグラウンド