Kotlin Reference を見ていて腑に落ちなかった点を掘り下げてみる

# あらすじ

毎朝、Kotlin Referenceの読み合わせをする勉強会をやっています。

現在、クラスと継承のところまで読み合わせをしたのですが、いくつか腑に落ちなかった点がありました。
[クラスと継承 - Kotlin Programming Language](https://dogwood008.github.io/kotlin-web-site-ja/docs/reference/classes.html#%E7%B6%99%E6%89%BF)

そこで、腑に落ちなかった以下の点について掘り下げてみました。

- プロパティ
- インターフェース

といっても、上記はKotlin Referenceで説明されていましたので、Referenceの内容も交えて少し掘り下げてみました。

# プロパティ

基本的には以下ページの内容を引用しています。
[プロパティとフィールド - Kotlin Programming Language](https://dogwood008.github.io/kotlin-web-site-ja/docs/reference/properties.html)

## プロパティの宣言

Kotlinのクラスは、プロパティを持つことができます。
 これらは、 var キーワードを使用して、ミュータブル（可変）として宣言することもでき、 val キーワードを使用するとイミュータブル（読み取り専用）にすることもできます。

```kotlin
public class Address { 
  public var name: String = ...
  public var street: String = ...
  public var city: String = ...
  public var state: String? = ...
  public var zip: String = ...
}
```

プロパティを使うにはJavaでのフィールドでやるように、ただ単純に名前で参照するだけで良いです：

```kotlin
fun copyAddress(address: Address): Address {
  val result = Address() // 'new' キーワードは Kotlin にありません
  result.name = address.name // アクセサが呼ばれる
  result.street = address.street
  // ...
  return result
}
```

## ゲッターとセッター

プロパティを宣言するための完全な構文は次のとおりです。

```
var <propertyName>: <PropertyType> [= <property_initializer>]
  [<getter>]
  [<setter>]
```

イニシャライザ、ゲッターとセッターは必須ではありません。
イニシャライザか基本クラスのメンバーからオーバライドされることが推測される場合は、プロパティの型も必須ではありません。

例：

```kotlin
var allByDefault: Int? // エラー：明示的なイニシャライザが必要、デフォルトのゲッターとセッターは暗黙
var initialized = 1 // これは Int 型を持ち、ゲッターとセッターも持つ
```

読み取り専用のプロパティ宣言の完全な構文は、ミュータブルのものと比べて2点異なります。
var の代わりに val で始まるのと、セッターを認めないことでです：

```kotlin
val simple: Int? // Int 型を持ち、デフォルトゲッターを持つ。コンストラクタ内で初期化が必要
val inferredType = 1 // Int 型を持ち、デフォルトゲッターを持つ
```

カスタムアクセサは普通の関数ととても似ていて、プロパティの中に宣言することができます。
ここでは、カスタムゲッターの例を示します：

```kotlin
val isEmpty: Boolean
  get() = this.size == 0
```

カスタムセッターは次のようになります：

```kotlin
var stringRepresentation: String
  get() = this.toString()
  set(value) {
    setDataFromString(value) // 文字列をパースして他のプロパティへ値を代入する
  }
```

慣例により、セッターの引数名は value ですが、別の名前が良いならそちらを選択することもできます。

アクセサの可視性を変更したり、アノテーションを付ける必要がありますが、デフォルトの実装を変更する必要がない場合は、その本体を定義せずにアクセサを定義することができます：

```kotlin
var setterVisibility: String = "abc"
  private set // セッターはプライベートでデフォルトの実装を持つ

var setterWithAnnotation: Any? = null
  @Inject set // セッターに Inject でアノテーションを付ける
```

## バッキングフィールド (Backing Fields)

Kotlinのクラスは、フィールドを持つことができません。
しかし、カスタムアクセサを使用するときにバッキングフィールドが必要になることがあります。
この目的のために、Kotlinは自動バッキングフィールドを提供します。
これにより、 field 識別子を使用してアクセスすることができます。

```kotlin
var counter = 0 // イニシャライザの value はバッキングフィールドへ直に書き込まれる
  set(value) {
    if (value >= 0)
      field = value
  }
```

バッキングフィールドとは、フィールドの実体のことです。
KotlinとJavaのコードを比較するとわかりやすいかと思います。

```kotlin
// Kotlin
class Human {
    val age = 20
        get() {
            println("Age is: $field")
            return field
        }
}
```

```java
// Java
public final class Human {
   private final int age = 20;

   public final int getAge() {
      String var1 = "Age is: " + this.age;
      System.out.println(var1);
      return this.age;
   }
}
```

引用：https://android.benigumo.com/20190517/backing-fields-properties-in-kotlin/

## バッキングプロパティ

「暗黙のバッキングフィールド」にそぐわないことをやりたい場合には、 バッキングプロパティ (backing property) を持つように必ずフォールバックさせることもできます：

```kotlin
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
  get() {
    if (_table == null)
      _table = HashMap() // 型パラメータが推論される
    return _table ?: throw AssertionError("他スレッドによってnullをセットされた")
  }
```

全ての点において、これはちょうどJavaと同じです。
なぜなら、privateプロパティへデフォルトゲッターとセッターでのアクセスが、関数呼び出しのオーバヘッドが無いように最適化されているためです。

まとめると、ゲッターやセッターの外でフィールドに直接アクセスしたいときなどに使います。（field 識別子に名前をつけるイメージ）
private なフィールドに"_"を付けて明示します。
こちらもKotlinとJavaのコードを比較するとわかりやすいかと思います。

```kotlin
// Kotlin
class Human {
    private val _age: Int = 20
    val age: Int
        get() {
            return _age
        }

     val printAge = {
         println("Age is: $_age")
     }
}
```

```java
// Java
public final class Human {
   private final int _age = 20;
   @NotNull
   private final Function0 printAge = (Function0)(new Function0() {
      public Object invoke() {
         this.invoke();
         return Unit.INSTANCE;
      }

      public final void invoke() {
         String var1 = "Age is: " + Human.this._age;
         System.out.println(var1);
      }
   });

   public final int getAge() {
      return this._age;
   }

   @NotNull
   public final Function0 getPrintAge() {
      return this.printAge;
   }
}
```

引用：https://android.benigumo.com/20190517/backing-fields-properties-in-kotlin/

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

メソッドのオーバーライドとルールは同じです。
オーバーライドするフィールドの可視性修飾子をopenにし、オーバーライド先のフィールドにoverrideを付けます。

```kotlin
open class A {
    open var stringRepresentation: String = ""
        get() = field // バッキングフィールド
        set(value) {
            field = value.toUpperCase()
        }
}

class B : A() {
    override var stringRepresentation: String = ""
        get() = field.reversed()
        set(value) {
            field = value.toLowerCase()
        }
}

val a = A()
a.stringRepresentation = "abcde" // ABCDE

val b = B()
b.stringRepresentation = "abcde" // edcba
```

ちなみに、オーバーライドする際に型を変更することはできません。
（たとえ型が親子関係であっても）

```kotlin
open class A {
    open var stringRepresentation: CharSequence = ""
        get() = field // バッキングフィールド
        set(value) {
            field = value
        }
}

class B : A() {
    // var-property type is 'String', which is not a type of overridden
    override var stringRepresentation: String = ""
        get() = field
        set(value) {
            field = value
        }
}
```

# インターフェース

基本的には以下ページの内容を引用しています。
[インタフェース - Kotlin Programming Language](https://dogwood008.github.io/kotlin-web-site-ja/docs/reference/interfaces.html)

Kotlinでのインタフェースは、Java 8と非常によく似ています。
インタフェースは抽象メソッドの宣言と同様に、メソッドの実装を含めることができます。抽象クラスと違って、インタフェースは状態を持てません。
インタフェースはプロパティを持つことができますが、これらは abstract であること、またはアクセサの実装を提供することが必要です。
インタフェースは、 interface キーワードを使用して定義されます。

```kotlin
interface MyInterface {
    fun bar()
    fun foo() {
      // 本体は任意
    }
}
```

ちなみに、Java 8におけるインターフェースについては以下を参考にしてください。
多重継承の問題についても考察されています。
[Java8のインタフェース実装から多重継承とMix-inを考える | ギークを目指して](http://equj65.net/tech/java8mixin/)
→どうやら、Java 8とKotlinで多重継承の解決方法は同じのようです。

## インタフェースの実装

クラスやオブジェクトは、1つまたは複数のインターフェイスを実装することができます：

```kotlin
class Child : MyInterface {
   override fun bar() {
      // 本体
   }
}
```

## インターフェイス内のプロパティ

インターフェイス内にプロパティを宣言することができます。
インタフェースで宣言されたプロパティは、 abstract にすることも、アクセサの実装を提供することもできます。
インタフェース内で宣言されたプロパティはバッキングフィールドを持つことはできず、それ故にインタフェース内で宣言されたアクセサはそれらを参照できません。

```kotlin
interface MyInterface {
    val property: Int // abstract

    val propertyWithImplementation: String
        get() = "foo"

    fun foo() {
        print(property)
    }
}

class Child : MyInterface {
    override val property: Int = 29
}
```

## オーバーライドの競合解決

スーパータイプのリストでたくさんの型を宣言すると、同メソッドの複数の実装を継承するように見えることがあります。例えば：

```kotlin
interface A {
  fun foo() { print("A") }
  fun bar()
}

interface B {
  fun foo() { print("B") }
  fun bar() { print("bar") }
}

class C : A {
  override fun bar() { print("bar") }
}

class D : A, B {
  override fun foo() {
    super<A>.foo()
    super<B>.foo()
  }
}
```

インタフェース A と B は、両方とも関数 foo() と bar() を宣言しています。
両方とも foo() を実装していますが、 B のみが bar() を実装しています。
（ bar() は A では abstract としてマークされていません。これは関数が本体を持たないときのインタフェースのデフォルトだからです。） 
さて、もし具体クラス C を A から得れば、 bar() をオーバライドし、実装を提供しなければならないことは明らかです。
そしてもし D を A と B から得れば、 bar() をオーバライドする必要はありません。
なぜなら1つの実装を継承したからです。
 しかし foo() の実装を2つ継承してしまったため、コンパイラはどっちを選んだら良いかわかりません。
したがって foo() のオーバライドが強制され、何が欲しいのかを明示する必要があります。