※本サイトで紹介している商品・サービス等の外部リンクには、アフィリエイト広告が含まれる場合があります。

11. ジェネリクス (Generics)、総称型

2023年10月7日

概要

ジェネリクスは、Kotlinを含む多くの現代的なプログラミング言語で重要な機能です。これは、コードの再利用性を高め、型安全性を確保するための非常に強力なツールです。

ジェネリクスは、型をパラメータとして扱うことを可能にします。これにより、特定の型に依存せずにクラス、インターフェース、関数を定義でき、具体的な型はジェネリクスを使用する際に指定します。

ジェネリクス、ジェネリックプログラミング

ジェネリクス(またはジェネリックプログラミング)は、同じコードで異なる型のデータを処理できる仕組みです。

Kotlinは静的型付け言語で、コンパイル時にデータの型が決まります。通常、同じ処理を複数のデータ型に対して行う場合、似たようなコードを複数書く必要がありますが、ジェネリクスを使うことで、型を引数として渡すことができ、具体的なデータ型に依存しない汎用的なコードを記述できます。

これにより、コードの冗長性が減り、可読性が向上します。

書式

定義の際にクラス名や関数名の直後に < > (山かっこ) で囲んで型パラメータを宣言します。

class クラス名<型パラメータ名> {
}

例えば、汎用の箱としてクラスを定義し、この際ジェネリクスでクラスの定義ブロック内のデータの型をパラメータとして渡せるようにします。

// ジェネリクスを使用した Box クラス
class Box<T>(value: T) {
    var value: T = value
}

fun main() {
    val intBox: Box<Int> = Box<Int>(1)
    val stringBox: Box<String> = Box<String>("Hello")

    println(intBox.value) // 1
    println(stringBox.value) // Hello
}

実行結果

1
Hello

ジェネリクスを用いずに記載してみると

ジェネリクスを用いずに、型ごとにクラスを用意した例です。似たような定義のクラスを複数記述する都合上コード自体が長くなります。

class IntBoxClass(value: Int){
    var value: Int = value
}

class StringBoxClass(value : String){
    var value: String = value
}

fun main(){
    val intBox1 = IntBoxClass(1)
    val stringBox1 = StringBoxClass("Hello")

    println(intBox1.value) // 1
    println(stringBox1.value) // Hello
}

実行結果

1
Hello

または、Any 型を使用する形でも記載できますが、この場合は型安全性が確保されません。

class anyBox(value: Any) {
    var value: Any = value
}

fun main() {
    val intBox2= anyBox(1 as Int)
    val stringBox2= anyBox("Hello" as String)

    println(intBox2.value)  // 1 
    println(stringBox2.value) // Hello

}