kotlinで定数を定義する時【const】vs【val】

# kotlinで定数を定義する

kotlinで定数を定義する際にはCompanionObjectが使われます。
定数を定義する際にプリミティブ型かStringsであれば`const`をつけることができますが、`const`がある時とない時の振る舞いの違いを調べてみました。

```kotlin
class Constants {  
  companion object {
    const val NAME = "taku"
  }
}
```


# constをつけずに定数を定義した場合

```kotlin
class Constants {  
  companion object {
    val NAME = "taku"
  }
}
```

これをバイトコードで見てみると、

```java
// ================com/hoge/Constants.class =================
// class version 50.0 (50)
// access flags 0x31
public final class com/hoge/Constants {


  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 6 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lcom/hoge/Constants; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x1A
  private final static Ljava/lang/String; NAME = "taku"
  @Lorg/jetbrains/annotations/NotNull;() // invisible

  // access flags 0x8
  static <clinit>()V
    NEW com/hoge/Constants$Companion
    DUP
    ACONST_NULL
    INVOKESPECIAL com/hoge/Constants$Companion.<init> (Lkotlin/jvm/internal/DefaultConstructorMarker;)V
    PUTSTATIC com/hoge/Constants.Companion : Lcom/hoge/Constants$Companion;
   L0
    LINENUMBER 9 L0
    LDC "taku"
    PUTSTATIC com/hoge/Constants.NAME : Ljava/lang/String;
    RETURN
    MAXSTACK = 3
    MAXLOCALS = 0

  // access flags 0x19
  public final static Lcom/hoge/Constants$Companion; Companion

  // access flags 0x1019
  public final static synthetic access$getNAME$cp()Ljava/lang/String;
  @Lorg/jetbrains/annotations/NotNull;() // invisible
   L0
    LINENUMBER 6 L0
    GETSTATIC com/hoge/Constants.NAME : Ljava/lang/String;
    ARETURN
   L1
    MAXSTACK = 1
    MAXLOCALS = 0

  @Lkotlin/Metadata;(mv={1, 1, 6}, bv={1, 0, 1}, k=1, d1={"\u0000\u000c\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\u0008\u0003\u0018\u0000 \u00032\u00020\u0001:\u0001\u0003B\u0005\u00a2\u0006\u0002\u0010\u0002\u00a8\u0006\u0004"}, d2={"Lcom/hoge/Constants;", "", "()V", "Companion", "production sources for module hoge"})
  // access flags 0x19
  public final static INNERCLASS com/hoge/Constants$Companion com/hoge/Constants Companion
  // compiled from: Constants.kt
}


// ================com/hoge/Constants$Companion.class =================
// class version 50.0 (50)
// access flags 0x31
public final class com/hoge/Constants$Companion {


  // access flags 0x11
  public final getNAME()Ljava/lang/String;
  @Lorg/jetbrains/annotations/NotNull;() // invisible
   L0
    LINENUMBER 9 L0
    INVOKESTATIC com/hoge/Constants.access$getNAME$cp ()Ljava/lang/String;
    ARETURN
   L1
    LOCALVARIABLE this Lcom/hoge/Constants$Companion; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x2
  private <init>()V
   L0
    LINENUMBER 8 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lcom/hoge/Constants$Companion; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x1001
  public synthetic <init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
   L0
    LINENUMBER 8 L0
    ALOAD 0
    INVOKESPECIAL com/hoge/Constants$Companion.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lcom/hoge/Constants$Companion; L0 L1 0
    LOCALVARIABLE $constructor_marker Lkotlin/jvm/internal/DefaultConstructorMarker; L0 L1 1
    MAXSTACK = 1
    MAXLOCALS = 2

  @Lkotlin/Metadata;(mv={1, 1, 6}, bv={1, 0, 1}, k=1, d1={"\u0000\u0014\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\u0008\u0002\n\u0002\u0010\u000e\n\u0002\u0008\u0003\u0008\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\u0008\u0002\u00a2\u0006\u0002\u0010\u0002R\u0014\u0010\u0003\u001a\u00020\u0004X\u0086D\u00a2\u0006\u0008\n\u0000\u001a\u0004\u0008\u0005\u0010\u0006\u00a8\u0006\u0007"}, d2={"Lcom/hoge/Constants$Companion;", "", "()V", "NAME", "", "getNAME", "()Ljava/lang/String;", "production sources for module hoge"})
  // access flags 0x19
  public final static INNERCLASS com/hoge/Constants$Companion com/hoge/Constants Companion
  // compiled from: Constants.kt
}

```

色々書かれてありますが、NAMEの部分を見てみると、Companionクラスの中の`getNAME()`というメソッドを通してNAMEにアクセスしていることが分かります。

javaからだと、`Constants.Companion.getNAME()`でNAMEにアクセスできます。


# constをつけて定数を定義した場合

```kotlin
class Constants {
  companion object {
    const val NAME = "taku"
  }
}
```

これをバイトコードで見てみると、

```java
// ================com/hoge/Constants.class =================
// class version 50.0 (50)
// access flags 0x31
public final class com/hoge/Constants {


  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 6 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lcom/hoge/Constants; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x19
  public final static Ljava/lang/String; NAME = "taku"
  @Lorg/jetbrains/annotations/NotNull;() // invisible

  // access flags 0x8
  static <clinit>()V
    NEW com/hoge/Constants$Companion
    DUP
    ACONST_NULL
    INVOKESPECIAL com/hoge/Constants$Companion.<init> (Lkotlin/jvm/internal/DefaultConstructorMarker;)V
    PUTSTATIC com/hoge/Constants.Companion : Lcom/hoge/Constants$Companion;
    RETURN
    MAXSTACK = 3
    MAXLOCALS = 0

  // access flags 0x19
  public final static Lcom/hoge/Constants$Companion; Companion

  @Lkotlin/Metadata;(mv={1, 1, 6}, bv={1, 0, 1}, k=1, d1={"\u0000\u000c\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\u0008\u0003\u0018\u0000 \u00032\u00020\u0001:\u0001\u0003B\u0005\u00a2\u0006\u0002\u0010\u0002\u00a8\u0006\u0004"}, d2={"Lcom/hoge/Constants;", "", "()V", "Companion", "production sources for module hoge"})
  // access flags 0x19
  public final static INNERCLASS com/hoge/Constants$Companion com/hoge/Constants Companion
  // compiled from: Constants.kt
}


// ================com/hoge/Constants$Companion.class =================
// class version 50.0 (50)
// access flags 0x31
public final class com/hoge/Constants$Companion {


  // access flags 0x2
  private <init>()V
   L0
    LINENUMBER 7 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lcom/hoge/Constants$Companion; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x1001
  public synthetic <init>(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
   L0
    LINENUMBER 7 L0
    ALOAD 0
    INVOKESPECIAL com/hoge/Constants$Companion.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lcom/hoge/Constants$Companion; L0 L1 0
    LOCALVARIABLE $constructor_marker Lkotlin/jvm/internal/DefaultConstructorMarker; L0 L1 1
    MAXSTACK = 1
    MAXLOCALS = 2

  @Lkotlin/Metadata;(mv={1, 1, 6}, bv={1, 0, 1}, k=1, d1={"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\u0008\u0002\n\u0002\u0010\u000e\n\u0000\u0008\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\u0008\u0002\u00a2\u0006\u0002\u0010\u0002R\u000e\u0010\u0003\u001a\u00020\u0004X\u0086T\u00a2\u0006\u0002\n\u0000\u00a8\u0006\u0005"}, d2={"Lcom/hoge/Constants$Companion;", "", "()V", "NAME", "", "production sources for module hoge"})
  // access flags 0x19
  public final static INNERCLASS com/hoge/Constants$Companion com/hoge/Constants Companion
  // compiled from: Constants.kt
}

```

constをつけた場合には、Companionクラスは存在していますが、getNAMEメソッドがなくなって、Companionクラスを介さずに直接NAMEにアクセスすることができます。

javaからだと、`Constants.NAME`でNAMEにアクセスできます。

# まとめ

- constをつけるとgetXXX()がなくなるのでメソッド数が減る。
- constをつけるとgetXXX()メソッドを一つ挟まずに直接変数にアクセスする。

constがつけれるときはつけたほうが良さそう。