Kotlinまとめ - 文法詳解 - 継承と抽象クラス

# クラスの継承
* インタフェースに準拠するときと同じように、クラス名の定義の後に`:`でつなげる
* 継承元:スーパークラス、継承先:サブクラス
* 継承元のクラスは`open`を指定しないと継承不可

```Kotlin
open class Person(val name: String) {
    fun introduceMyself() {
        println("I am $name")
    }
}

class Student(name: String, val id: Long): Person(name)
```

# メンバのオーバーライド
* オーバーライドもデフォルトで禁止されており、プロパティやメソッドに`open`を付ける必要がある
* スーパークラスのメンバを呼び出すときは`super.メンバ`

```Kotlin
open class Person(val name: String) {
    open fun introduceMyself() {
        println("I am $name")
    }
}

class Student(name: String, val id: Long): Person(name) {
    override fun introduceMyself() {
        super.introduceMyself()
        println("id=$id")
    }
}

val student = Student("hicka04", 123)
student.introduceMyself()  // I am hicka04 \n id=123
```

# スーパータイプとサブタイプ
* クラスを定義することで型を得られる
    * スーパークラス:スーパータイプ
    * サブクラス:サブタイプ
* サブタイプのオブジェクトは、スーパータイプのオブジェクトとして扱うことができる
    * スーパータイプにないメンバはアクセス不能
    * アクセスすると実態はサブタイプの方にアクセスしている

```Kotlin
val person: Person = Student("hicka04", 123)
person.introduceMyself()  // I am hicka04 \n id=123
person.id  // コンパイルエラー
```

# Any
* すべてのクラスが継承している暗黙的な型
* すべてのオブジェクトに共通する基本的なメソッドを提供している

```Kotlin
public open fun toString(): String
public open operator fun equals(other: Any?): Boolean
public open fun hashCode(): Int
```

# 抽象クラス
* メンバのオーバーライドをサブクラスに強制する仕組み
* メソッドやプロパティに`abstruct`をつける → 抽象メンバ
* 抽象メンバをもつクラスは抽象クラスで、インスタンス化はできない
* `abstruct`がついている抽象メンバはオーバーライド必須なので`open`キーワードは不要

```Kotlin
abstract class Greeter(val target: String) {
    abstract fun sayHello()
}

class EnglishGreeter(target: String): Greeter(target) {
    override fun sayHello() {
        println("Hello, $target")
    }
}

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

EnglishGreeter("Kotlin").sayHello() // Hello, Kotlin
JapaneseGreeter("Java").sayHello()  // こんにちは、Java
```

# 可視性
## パッケージ
* Javaと同様にパッケージで名前空間を区切る
* パッケージ直下には以下の要素を宣言できる
    * 関数
    * プロパティ
    * クラス
    * インタフェース
    * オブジェクト
* 同一のパッケージ内に同名のクラスを複数定義することはできない  
  ⇔異なるパッケージであれば同名のクラスを定義可能

```Kotlin
package sample.hoge
class Foo
```

* `Foo`は`sample.hoge`に属する
    * 完全修飾名は`sample.hoge.Foo`
* 同一パッケージ内であれば`Foo`でアクセス可能
* 異なるパッケージから呼ぶときは`sample.hoge.Foo`でアクセスする必要がある
    * `import`することで`Foo`だけで呼べるようになる

```Kotlin
package sample.fuga
import sample.hoge.Foo
import sample.fuga.Buz as Beer
class Baz

class Bar {
    fun doSomething() {
        sample.hoge.Foo()
        Foo()  // importしてるのでこれでOK
        Berr() // 別名インポートしているのでOK
    }
}
```

## トップレベルにおける可視性修飾子
* パッケージ直下に宣言できる関数やクラスなどに可視性修飾子をつけることで公開範囲を調整できる

| 修飾子   | 公開範囲                                     | 備考       |
|----------|----------------------------------------------|------------|
| public   | 公開範囲に制限はなく、どこからでもアクセス可 | デフォルト |
| internal | 同一のモジュール内に限り全公開               |            |
| private  | 同一ファイル内のみアクセス可能               |            |

## クラスにおける可視性修飾子
クラスやインタフェースのメンバにつける可視性修飾子

| 修飾子    | 公開範囲                                     | 備考       |
|-----------|----------------------------------------------|------------|
| public    | 公開範囲に制限はなく、どこからでもアクセス可 | デフォルト |
| internal  | 同一のモジュール内に限り全公開               |            |
| protected | 同一クラス内とサブクラス内からアクセス可     |            |
| private   | 同一クラス内のみアクセス可能                 |            |

```Kotlin
// プライマリコンストラクタにつけるときは`constructor`を省略できない
open class Hoge private constructor()
```

---

[← 文法詳解 - クラスとそのメンバ](https://qiita.com/hicka04/items/6f47f505d7b68ede3680) || [文法詳解 - インタフェース →](https://qiita.com/hicka04/items/9922c8342ff8a8fcda8a)