kotlinのcompanionとcompanion objectをちゃんとまとめる。

javaでよくあるユーティリティクラスをkotlinに移植しようと思ったときに気づきがあったのでまとめておく。


#### javaユーティリティクラスのkotlin convert

事の発端はjavaで記述された以下のユーティリティクラス（staticなメンバーのみをもつクラス）をkotlinにconvertしたとき、`object SampleUtil` で定義されていたこと。kotlinでobjectを定義するとsingletonになるはずで、本来インスタンスを生成しないはずのものがsingletonに変換されていることを不思議に思った。

例えばaws-android-sdkにあったこのSampleUtil、
これをkotlinにconvertすると、

```java
public class SampleUtil {
    private static final String PropertyFile = "aws-iot-sdk-samples.properties";

    public static class KeyStorePasswordPair {
        public KeyStore keyStore;
        public String keyPassword;

        public KeyStorePasswordPair(KeyStore keyStore, String keyPassword) {
            this.keyStore = keyStore;
            this.keyPassword = keyPassword;
        }
    }
...
}

```

SampleUtilはobjectで定義されていて、staticだったものがsingletonに変換される。

```kotlin
object SampleUtil {
    private val PropertyFile = "aws-iot-sdk-samples.properties"

    class KeyStorePasswordPair(var keyStore: KeyStore, var keyPassword: String)

    fun getConfig(name: String): String? {
        val prop = Properties()
        val resource = SampleUtil::class.java.getResource(PropertyFile) ?: return null
        try {
            resource.openStream().use { stream -> prop.load(stream) }
        } catch (e: IOException) {
            return null
        }

        val value = prop.getProperty(name)
        return if (value == null || value.trim { it <= ' ' }.length == 0) {
            null
        } else {
            value
        }
    }
...
}
```

kotlinで`object`で定義するsingletonになることは知識としては前から知っていたので、javaにおけるユーティリティクラス(staticメンバのみを持つクラス）をkotlinにconvertすると `class SampleUtil`内の`companion object` にメンバーを定義する形になると想像していたが結果は違った。また多くのピュアkotlinで書かれたプロジェクトのユーティリティクラスも同じように`object`でシングルトンを生成していたことも混乱する原因となった。


#### objectとcompanion objectのおさらい
詳細は以下にまとまっているが、改めて`object`と`companion object`のおさらいをする。
[https://kotlinlang.org/docs/reference/object-declarations.html:title]

`object`で定義した`DataProviderManager`はシングルトンで生成され、

```kotlin
object DataProviderManager {
  fun registerDataProvider(provider: DataProvider) {
    // ...
  }

  val allDataProviders: Collection<DataProvider>
    get() = // ...
}
```

`DataProviderManager.registerDataProvider(...)` のように使える。

`companion object` についても同じように、

```kotlin
class MyClass {
    companion object Factory {
        fun create(): MyClass = MyClass()
    }
}
```

`val instance = MyClass.create()` のように使える。

`object`がsingletonということは`companion object`はstaticだろうと思っていたのが勘違いの始まりでちゃんとドキュメントを読むと以下のようにstaticに見えるメンバーもオブジェクトインスタンスのメンバーであるという記述がある。

> Note that, even though the members of companion objects look like static members in other languages, at runtime those are still instance members of real objects, and can, for example, implement interfaces:

#### objectとcompanion objectはjavaでどう解釈されるか

公式ドキュメントによれば`object`も`companion object`も非staticでありインスタンスは生成されているということだが、実際にjavaではどのように解釈されるのか、
理解を深めるために実際に以下のktクラスをdecompileした。

##### object

```kotlin
object SampleUtil1 {
    fun test() {
        Log.e("SampleUtil1", "test")
    }
}
```

```java
@Metadata(
   mv = {1, 1, 11},
   bv = {1, 0, 2},
   k = 1,
   d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\bÆ\u0002\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\u0006\u0010\u0003\u001a\u00020\u0004¨\u0006\u0005"},
   d2 = {"Lcom/hoge/util/asset/SampleUtil1;", "", "()V", "test", "", "production sources for module app"}
)
public final class SampleUtil1 {
   public static final SampleUtil1 INSTANCE;

   public final void test() {
      Log.e("SampleUtil2", "test");
   }

   static {
      SampleUtil1 var0 = new SampleUtil1();
      INSTANCE = var0;
   }
}
```

##### companion object

```kotlin
class SampleUtil2 {
    companion object {
        fun test() {
            Log.e("SampleUtil2", "test")
        }
    }
}
```

```java
@Metadata(
   mv = {1, 1, 11},
   bv = {1, 0, 2},
   k = 1,
   d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0003\u0018\u0000 \u00032\u00020\u0001:\u0001\u0003B\u0005¢\u0006\u0002\u0010\u0002¨\u0006\u0004"},
   d2 = {"Lcom/hoge/util/asset/SampleUtil2;", "", "()V", "Companion", "production sources for module app"}
)
public final class SampleUtil2 {
   public static final SampleUtil2.Companion Companion = new SampleUtil2.Companion((DefaultConstructorMarker)null);

   @Metadata(
      mv = {1, 1, 11},
      bv = {1, 0, 2},
      k = 1,
      d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\u0006\u0010\u0003\u001a\u00020\u0004¨\u0006\u0005"},
      d2 = {"Lcom/hoge/util/asset/SampleUtil2$Companion;", "", "()V", "test", "", "production sources for module app"}
   )
   public static final class Companion {
      public final void test() {
         Log.e("SampleUtil2", "test");
      }

      private Companion() {
      }

      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}
```


metadataとかがあって弱化読みにくいが、SampleUtil1については想定どおりでstaticイニシャライザでSampleUtil1をシングルトンで生成している。
一方`companion object` のほうはというと、`companion object` 内で定義したメンバーはsitaticインナークラスで定義されたCompanionクラス内に定義されている。
SampleUtil2自体はインスタンス化されていないが内部のCompanionクラスがシングルトンで生成されるのでやっていることとしてはシングルトンインスタンスを作るということで`object`定義のほうと大きな差はないように思う。

#### 結論
- kotlinではstaticを許容しない
- `companion object` も `object` もシングルトンインスタンスを生成する