Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Kotlinスタートブック読書勉強会 第10章 補足

Kotlinスタートブック読書勉強会 第10章 補足


reference や他のサイトなどに記述があって、赤べこ本では割愛されている(または ver1.1 以降の)内容の引用 が中心


1. Interface の 定義と実装

interface の method にも デフォルト引数 定義可能

// list 10.9 を 改修
interface Greeter {
    fun sayHello(target: String = "匿名")
}

class JapaneseGreeter : Greeter {
    override fun sayHello(target: String) {
        println("こんにちは, ${target}さん!")
    }
}

fun main(args: Array<String>) {
    val greeter = JapaneseGreeter()
    greeter.sayHello()           // こんにちは, 匿名さん!
    greeter.sayHello("たろう")   // こんにちは, たろうさん!
}
  • 第9章 の 補足 に記述したとおり, override 先で デフォルト引数 を指定するとエラー

2. デフォルト実装 と コンフリクトの回避


4. Delegation

list 10.12 class delegation を使った例

interface AListener {
    fun a1(); fun ab()
}
class AAdapter : AListener {
    override fun a1() = println("AAdapter:a1")
    override fun ab() = println("AAdapter:ab")
}

interface BListener {
    fun b1(); fun ab()
}
class BAdapter : BListener {
    override fun b1() = println("BAdapter:b1")
    override fun ab() = println("BAdapter:ab")
}

// ★ 複数 の class delegation
class MyListener(private val a: AListener, private val b: BListener) : AListener by a, BListener by b {
    override fun ab() { // `ab` の定義が衝突しているので override しないと コンパイルエラー
        b.ab()
    }
}

fun main(args: Array<String>) {
    val l = MyListener(AAdapter(), BAdapter())
    l.a1()  // AAdapter:a1
    l.b1()  // BAdapter:b1
    l.ab()  // BAdapter:ab
}

Effective java に掲載されている例 (項目16)

class InstrumentedHashSet<E> : HashSet<E>() {
    var addCount: Int = 0

    override fun add(e: E): Boolean {
        addCount++
        return super.add(e)
    }

    override fun addAll(c: Collection<E>): Boolean {
        addCount += c.size
        return super.addAll(c)
    }
}

fun main(args: Array<String>) {
    val s1 = InstrumentedHashSet<String>()
    s1.add("a")
    s1.add("b");
    println(s1.addCount)   // 2

    val s2 = InstrumentedHashSet<String>()
    s2.addAll(arrayOf("x", "y", "z"))
    println(s2.addCount)   // 6
}
  • 3 を期待していたのに 結果は 6
    • super.addAll の中で add が呼ばれているため

委譲に変更した例

// 変更したのは先頭行のみ. 他の実装は 継承の場合 と一緒
class InstrumentedHashSet<E>(private val s: MutableSet<E>) : MutableSet<E> by s {
    var addCount: Int = 0

    override fun add(e: E): Boolean {
        addCount++
        return s.add(e)
    }

    override fun addAll(c: Collection<E>): Boolean {
        addCount += c.size
        return s.addAll(c)
    }
}

fun main(args: Array<String>) {
    val s1 = InstrumentedHashSet(HashSet<String>()) // コンストラクタ で 委譲先 の インスタンス を渡す
    s1.add("a")
    s1.add("b");
    println(s1.addCount)   // 2

    val s2 = InstrumentedHashSet(HashSet<String>()) // 同上
    s2.addAll(arrayOf("x", "y", "z"))
    println(s2.addCount)   // 3
}

Effective java に掲載されている例 (項目17)

import java.time.LocalDateTime

fun Super.s() = println("... init start (${javaClass.kotlin.simpleName})")
fun Super.e() = println("... init end   (${javaClass.kotlin.simpleName})")
fun p() = println("-----------------------------")

abstract class Super {
    init {
        s()
        overrideMe() // ★[NG] コンストラクタ が override 可能なメソッドを呼び出し
        e()
    }
    abstract fun overrideMe()
}

class Sub : Super() {
    private var date = LocalDateTime.now()

    // ★ super クラス の init 呼び出し時点では `date` は まだ `null`
    override fun overrideMe() = println(date)
}

class Sub2 : Super() {
    private var date = LocalDateTime.now()

    init { // 親の init が 呼ばれた後, 実行される
        s()
        overrideMe() // sub クラス の init 呼び出し時点では `date` は 初期化済み
        e()
    }
    override fun overrideMe() = println(date)
}

fun main(args: Array<String>) {
    Sub()
    p()
    Sub2()
}
  • 実行結果
... init start (Sub)
null
... init end   (Sub)
-----------------------------
... init start (Sub2)
null
... init end   (Sub2)
... init start (Sub2)
2017-11-27T18:32:08.281
... init end   (Sub2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.