Java開発者に送るKotlinのClass part.2

# 可視性
JavaとKotlinの可視性はやや異なります。

* Kotlinのデフォルト可視性は`public`
* Kotlinに`package private`は無い
* Kotlin独自の可視性`internal`がある (同一モジュール内で参照可)
* Kotlinはデフォルトで継承不可 (Javaのfinal扱い)

# 継承
KotlinでAnimalクラスを継承したDogクラスを定義してみます。

```kotlin
open class Animal { // 継承可なクラスにするためopenをつける
    open fun greet() { // オーバーライド可能な関数にするためopenをつける
    }
}

class Dog: Animal() { // コロンに続けて親クラス名を
    override fun greet() { // override修飾子をつける
        println("Bow wow")
    }
}
```

クラスを継承するときは、
class `サブクラス名`: `スーパークラスのコンストラクタ` と記述します。

コンストラクタに引数が必要な場合を見てみましょう。

```kotlin
open class Animal(val name: String) {
    open fun greet() {
    }
}

// Dogのコンストラクタ引数 `name` をAnimalクラスのコンストラクタに渡す
class Dog(name: String): Animal(name) {
    override fun greet() {
        println("Bow wow")
    }
}
```

# コンパニオンオブジェクト
Kotlinにはstatic修飾子はありません。

Kotlinのクラスでstaticメンバやstatic関数を扱いたい場合は、
コンパニオンオブジェクトを使います。

コンパニオンオブジェクトとは、
特別なシングルトンインスタンスです。

```kotlin
class Dog {
    companion object {
        val ancestorName: String = "wolf"
    }

    fun greet() {
        println("Bow wow")
    }
}

val ancestor = Dog.ancestorName
```

`companion object`の中で `ancestorName` というプロパティを定義しました。
このプロパティにアクセスするには `Dog.ancestorName` と、staticメンバのようにアクセスします。


※ただし、Javaとの互換性のため、staticとしてコンパイルするためのアノテーションは存在します。


# object宣言

Kotlinにはシングルトンを簡単に実装する仕組みがあります。

```kotlin
object ResourceManager {
    fun clean() {
        // ...
    }   
}

ResourceManager.clean()
```

`object`キーワードに続けてシングルトンなクラスを定義できます。
通常のクラスと同様にプロパティや関数を定義できますが、
object宣言ではコンストラクタだけ定義できません。
シングルトンなインスタンスにアクセスするにはクラス名を用います。
Javaのstaticメンバへのアクセスに似ています。

# dataクラス

データを保持するためのシンプルなクラスは、頻繁に実装しますよね？

```kotlin
data class Point(val x : Int, 
                 val y: Int) {
}
```

`data`キーワードに続けてクラスを定義します。
data classはプライマリコンストラクタで宣言されたプロパティを全て、以下の関数で考慮します。

* equals関数...一致チェックにプロパティの値を考慮
* hashCode関数...ハッシュ値生成にプロパティの値を考慮
* toString関数...プロパティの値を出力

また、copy関数が自動生成されます。
これは、任意のプロパティを変更しながらコピーすることができます。

```kotlin
fun moveTo(point: Point, newX: Int): Point {
    return point.copy(x = newX)
}
```

プロパティは全てvalで宣言し、クラスはImmutableとしながら、
値を書き換えたコピーは簡単に生成できます。

# sealedクラス
sealedクラスは同一ファイル内でしか継承できないクラスです。

```kotlin
sealed class Animal {
}

class Dog: Animal() {
}

class Cat: Animal() {
}
```

```kotlin
fun greet(animal: Animal) = when(animal) {
    is Dog -> "bow wow"
    is Cat -> "meow meow"
    // else -> elseケースは不要！
}
```

上記のgreet関数の中のwhenにご注目ください。
elseケースがありません。
これはsealedクラスの効果です。

# innerクラス

Javaではクラスの中にクラスを定義する場合、static修飾子をつけるか否かで意味合いが変わります。Kotlinの記述方法と比較してみます。

※あるクラスの中に定義されたAというクラス

|Java|Kotlin|
|:--|:--|
|static class A|class A|
|class A|inner class A|

Kotlinのデフォルトは
Javaの`static`付きネストクラスと同義となります。

# プロパティとバッキングフィールド

Kotlinのプロパティは1行で宣言できますが、
ゲッター、セッターをそれぞれカスタマイズすることが可能です。

```kotlin
class Dog(name: String) {

    var name: String = name
        get() { // カスタムゲッター
            // ゲッターの中ではfield変数が利用できる
            // このゲッターはnameに"ちゃん"をつけて返す
            return field + "ちゃん"
        }
        set(value) { // カスタムセッター
            // セッターは引数名を指定する
            // このセッターは名前の前から空白を除去してフィールドにセットする
            field = value.trimMargin()
        }

}
```

# デリゲート

Kotlinのクラスはデフォルトで継承不可です。
継承をせずに機能を拡張していく仕組みがあります。

Movableというインターフェースと、
Movableを実装したMovableImplクラスを定義しました。

```kotlin
interface Movable {
    fun walk()
    fun run()
    fun currentCount(): Int
}

class MovableImpl: Movable {

    private var count: Int = 0

    override fun walk() {
        this.count += 1
    }
    override fun run() {
        this.count += 3
    }
    override fun currentCount(): Int = this.count
}
```

このMovableの機能を拡張したDogクラスを定義します。

```kotlin
class Dog(movable: MovableImpl): Movable by movable {

}
```

`by`キーワードに続けて、Movableの機能を委譲するインスタンスを指定します。
このDogクラスはMovableインターフェースに関する実装が何もありませんが、
自動的にMovableImplに委譲されます。

```kotlin
val dog = Dog(MovableImpl())
dog.walk()
dog.walk()
dog.run()

println(dog.currentCount()) // 5
```

# プロパティデリゲート

プロパティのゲッター、セッターの振る舞いを委譲することができます。
このようなクラスを定義します。

```kotlin
class Dog {
    var name: String by NameFormatter()
}

class Cat {
    var name: String by NameFormatter()
}
```

DogクラスもCatクラスもnameというプロパティを持ちます。
どちらも`by`に続いてNameFormatterを指定しています。
下のコードを実行してみます。

```kotlin
val dog = Dog()
dog.name = "        ぽち"
println(dog.name) //ぽちちゃん
val cat = Cat()
cat.name = "        たま"
println(cat.name) //たまちゃん
```

いずれも、nameに代入した文字列から空白を除去し、
ゲッターではサフィックスとして"ちゃん"が付加されています。

それでは、NameFormatterの実装を見てみましょう。

```kotlin
class NameFormatter {

    private var name: String = ""

    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return this.name + "ちゃん"
    }
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        this.name = value.trimStart()
    }
}
```

`operator`キーワードに続けて、`getValue`メソッドと`setValue`メソッドを実装します。

このように、プロパティの挙動を外部に委譲することができます。