1. 概要

このクイックチュートリアルでは、Kotlinプログラミング言語のクラスとオブジェクトの違いに光を当てます。

その過程で、さらに深く掘り下げて、各抽象化がバイトコードレベルでどのように表されるかを見ていきます。

2. クラス表現

Kotlinのクラスは、概念的にはJavaのクラスに似ています:インスタンスを作成するための青写真です。

class Person {
    // omitted
}

上記の例では、Kotlinコンパイラはバイトコードレベルで一般的なクラス定義を生成します。

>> kotlinc Person.kt
>> javap -c -p -v com.baeldung.classobject.Person
public final class com.baeldung.classobject.Person
  // omitted
  flags: (0x0031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER
  this_class: #2        // com/baeldung/classobject/Person
  super_class: #4       // java/lang/Object
  interfaces: 0, fields: 0, methods: 1, attributes: 2

上に示したように、KotlinクラスはJavaクラスと同じようにコンパイルされますが、デフォルトでfinalになるなどの微妙な違いがいくつかあります。

Javaと同様に、具体的な(抽象ではない)Kotlinクラスからインスタンスまたはオブジェクトを作成することができます。

val p = Person()

また、拡張用にオープンである限り、通常のクラスから継承できます。

open class Person {
    // omitted
}

class User : Person() {
    // omitted
}

3. シングルトンオブジェクト

シングルトンとも呼ばれる、いくつかの抽象化のインスタンスを1つだけ持つと、ユースケースによっては便利な場合があります。 Kotlinでは、オブジェクト宣言を使用してそのようなシングルトンを作成できます

object FileSystem {
    
    fun createTempFile() {
        // omitted
    }
}

ここではFileSystemはシングルトンであるため、Javaではそのメンバーを静的メンバーとして扱うことができます。 簡単に言えば、そのメンバーにアクセスするためにファイルシステムをインスタンス化する必要はありません

fun main() {
    FileSystem.createTempFile()
}

単純なクラスとは対照的に、シングルトンのインスタンスを作成する必要はありません。 実際のところ、このようなインスタンスを作成することすらできません。

val f = FileSystem()

ここで、Kotlinコンパイラは、シングルトンオブジェクトからインスタンスを作成できないようにします。

シングルトンオブジェクト自体は他のクラスまたはインターフェイスを拡張できますが、継承することはできません。 具体的には、次のように書くことができます。

object FileSystem : Serializable {
    // omitted
}

ただし、以下は不可能であり、コンパイルされません。

class NTFS : FileSystem

3.1. バイトコード表現

内部的には、 Kotlinコンパイラは、FileSystemシングルトンオブジェクトをプライベートコンストラクタを使用して最終クラスに変換します。

>> kotlinc FileSystem.kt 
>> javap -c -p com.baeldung.classobject.FileSystem
public final class com.baeldung.classobject.FileSystem {
  private com.baeldung.classobject.FileSystem();
    Code:
       0: aload_0
       1: invokespecial #11    // Method java/lang/Object."<init>":()V
       4: return
}

その結果、他の誰もそれをインスタンス化できず、誰もそれを継承できません。

また、Java の従来のアプローチと同様に、static変数を使用してシングルトンインスタンスを保持します。

public final class com.baeldung.classobject.FileSystem {
  public static final com.baeldung.classobject.FileSystem INSTANCE;

  // omitted
}

この変数を初期化するために、Kotlinコンパイラはstatic初期化子を省略します。

static {};
    Code:
       0: new           #2    // class com/baeldung/classobject/FileSystem
       3: dup
       4: invokespecial #26   // Method "<init>":()V
       7: astore_0
       8: aload_0
       9: putstatic     #28   // Field INSTANCE:Lcom/baeldung/classobject/FileSystem;
      12: return

上記のように、最初に FileSystem インスタンスを作成し、次にそれをstaticシングルトンホルダーに割り当てます。

4. 結論

この短いチュートリアルでは、言語レベルとバイトコードレベルの両方で、Kotlinでクラスとオブジェクトがどのように異なるかを確認しました。 要約する:

  • シングルトンオブジェクトではなく、具象クラスからインスタンス化できます
  • シングルトンオブジェクトではなく、openクラスから継承できます

いつものように、すべての例はGitHubから入手できます。