クラス継承

kotlinlang.org

継承

すべてのKotlinのクラスは、Anyを継承している。

class Example // 暗黙的に Any を継承している

Anyは3つのメソッドを持っている。

  • equals()
  • hashCode()
  • toString()

クラスは、デフォルトは、finalであり、継承することができない。

// デフォルトは final がつけられる
class Parent

// This type is final, so it cannot be inherited from
class Child: Parent()

継承したい場合は、openキーワードを付ける必要がある。

open class Base // 継承することができる

継承は、クラスヘッダー部に、コロンのあとに型を置く。

open class Base(p: Int) 

// Baseを継承
class Derived(p: Int) : Base(p)

派生クラスがプライマリコンストラクタを持つならば、 継承クラスもそのプライマリコンストラクタのパラメーターを使って初期化する。

派生クラスがプライマリコンストラクタを持たない場合は、 セカンダリコンストラクタが、superキーワードを使ってbase型を初期化する必要がある。

class MyView : View {
    constructor(ctx: Context) : super(ctx)

    // セカンダリコンストラクタは異なるbaseのコンストラクタを呼ぶことができる
    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}

## メソッドのオーバーライド

open class Shape { open fun draw() { /.../ } fun fill() { /.../ } }

class Circle() : Shape() { override fun draw() { /.../ }

// NG fill' hides member of supertype 'Shape' and needs 'override' modifier
// fun fill() { /*...*/ }

}

オーバーライドするメソッドは、`override`修飾子をつける。

親クラスのオーバーライドメソッドを子クラスに禁止する場合は、`final`をつける

open class Rectangle() : Shape() { final override fun draw() { /.../ } }

## プロパティのオーバーライド

メソッドと同様にプロパティのオーバーライドもできる。
この際、型を揃える必要がある。また初期化もしくは、getメソッドを宣言する必要がある。
継承するにあたって、`val`から`var`に変更することができる。
(getメソッドに対して、setを追加的にオーバーライドすることが可能)

open class Shape { // 初期化しなかった場合 // Property must be initialized or be abstract // open val vertexCount: Int

open val vertexCount: Int = 0

}

class Rectangle : Shape() { override val vertexCount = 4 }

プライマリコンストラクタ内で、オーバーライドも可能。

interface Shape { // インターフェースのメンバはデフォルトopen val vertexCount: Int }

class Rectangle(override val vertexCount: Int = 4) : Shape

// varに変更も可能 class Rectangle(override var vertexCount: Int = 4) : Shape

## 派生クラスの初期化の順番

最初にベースクラスのコンストラクタに対する引数の評価処理され、
ベースクラスの初期化が完了後、派生クラスの初期化が実行される

open class Base(val name: String) {

init { println("Initializing a base class") }

open val size: Int = 
    name.length.also { println("Initializing size in the base class: $it") }

}

class Derived( name: String, val lastName: String, ) : Base(name.also { println("Argument for the base class: $it") }) {

init { println("Initializing a derived class") }

override val size: Int =
    (super.size + lastName.length).also { println("Initializing size in the derived class: $it") }

}

val d = Derived("tanaka", "yoshio")

/ 実行結果 Argument for the base class: tanaka Initializing a base class Initializing size in the base class: 6 Initializing a derived class Initializing size in the derived class: 12 /

## superclassメソッドへのアクセス

innerクラスからsuperクラスにアクセスするには、`super@Baseクラス`を使う

class FilledRectangle: Rectangle() { override fun draw() { val filter = Filter() filter.drawAndFill() }

inner class Filler {
    fun fill() { println("Filling") }
    fun drawAndFill() {
        super@FilledRectangle.draw() 
        fill()
    }
}

}


# まとめ感想

コンストラクタ周りカオスすぎ。
プライマリコンストラクタで宣言している変数がイニシャライザでも使えるというのもしっくりこない。