11. ジェネリクス (Generics)、総称型
概要
ジェネリクスは、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 }