プログラミング基礎概念

ジェネリクス じぇねりくす

型パラメータ型安全テンプレート型推論コレクション再利用性
ジェネリクスについて教えて

簡単に言うとこんな感じ!

「どんな種類のデータにも使える万能な入れ物」を作る仕組みだよ!たとえば「リスト」を作るとき、数字専用・文字専用と別々に作らなくても、「何でも入るリスト」として一度だけ作れるってこと!しかも使うときにはちゃんと型チェックもしてくれる優れモノなんだ!


ジェネリクスとは

ジェネリクス(Generics) とは、プログラムの「型(データの種類)」を、後から指定できるようにする仕組みです。たとえば「整数を入れるリスト」「文字列を入れるリスト」と別々に作るのではなく、「なんでも入れられるリスト」を一度だけ書いておき、使うときに「整数を入れる」「文字列を入れる」と指定できます。

ジェネリクスの最大のメリットは コードの再利用性型安全性 を同時に実現できる点です。「再利用性」とは同じコードをいろんなデータ型に使いまわせること。「型安全性」とは整数のリストに誤って文字列を入れようとしたとき、プログラムを動かす前にエラーとして検出できることです。

JavaC#KotlinTypeScriptRustなど、現代の主要なプログラミング言語のほぼすべてにジェネリクスの機能が備わっており、ライブラリやフレームワークの根幹をなす重要な概念です。


ジェネリクスの仕組みと構造

ジェネリクスは「型パラメータ」と呼ばれるプレースホルダーを使って書きます。慣習的に T(Type)や E(Element)などのアルファベット1文字が使われます。

概念意味例え
型パラメータ後から決める「型の仮置き文字」料理レシピの「お好みの具材」
ジェネリッククラス型パラメータを持つクラス何でも入る透明な箱
ジェネリックメソッド型パラメータを持つ関数サイズ指定できる万能工具
型引数実際に使うときに渡す具体的な型「具材=鶏肉」と決める行為
型推論コンパイラが型を自動で推測する機能文脈から「鶏肉だな」と察する
// ジェネリクスを使わない場合(型ごとに別々のクラスが必要)
class IntBox   { int value;    }
class StringBox { String value; }

// ジェネリクスを使った場合(1つで済む!)
class Box<T> { T value; }

// 使うとき
Box<Integer> intBox    = new Box<>();  // 整数入り
Box<String>  strBox    = new Box<>();  // 文字列入り

覚え方:「T シャツはどんな体型にも合う」

T(型パラメータ)は T シャツのTと同じ!Tシャツが「どんな体型の人にも着られる万能ウェア」であるように、<T> を使ったジェネリクスは「どんな型にも対応できる万能コード」です。

ジェネリクスの主な用途

用途具体例説明
コレクションList<String>Map<String, Integer>型安全なリストや辞書
汎用ユーティリティOptional<T>Future<T>結果を包む汎用ラッパー
アルゴリズムソート・検索の共通化型を問わない処理の共有
APIの戻り値Response<User>Result<T, E>返却データの型を明示

歴史と背景

  • 1973年 — ML言語でパラメータ多相(polymorphism)の概念が生まれ、ジェネリクスの原型が登場
  • 1980年代 — C++がテンプレートという形でジェネリクス相当の機能を実装。強力だが複雑でエラーメッセージが難解という課題もあった
  • 1990年代 — JavaやC#の初期バージョンにはジェネリクスがなく、Object型で代用していた。型変換ミスによる実行時エラーが頻発し、開発者を悩ませた
  • 2004年Java 5でジェネリクスが導入(JSR-14)。List<String> のような書き方が可能になり、型安全なコレクション操作が普及
  • 2005年C# 2.0でもジェネリクスが導入。Javaのものよりもランタイムレベルでサポートされ、パフォーマンス面でも優秀
  • 2010年代 — Kotlin・Swift・Rustなど新世代言語がジェネリクスをファーストクラスの機能として設計に組み込む
  • 現在 — TypeScriptの普及により、フロントエンド開発者にもジェネリクスが身近な概念となっている

ジェネリクスと型システムの全体像

ジェネリクスは「型の柔軟性」を扱う技術の一種です。似た概念との違いを整理しておきましょう。

技術概要型チェックのタイミング代表言語
ジェネリクス型パラメータで汎用化コンパイル時Java / C# / Kotlin
テンプレートコード生成による汎用化コンパイル時C++
ダックタイピングメソッドがあれば型不問実行時Python / Ruby
any型型チェックを放棄なしTypeScript(非推奨)
オーバーロード型ごとに別々に定義コンパイル時Java / C#

ジェネリクスが型システムの中でどう位置づけられるか、図解で確認しましょう。

型の柔軟性アプローチ比較 アプローチ 型安全 再利用性 チェックタイミング ジェネリクス ◎ 高い ◎ 高い コンパイル時 テンプレート ○ 高い ◎ 高い コンパイル時 ダックタイピング △ 低い ○ 高い 実行時 any型 ✕ なし △ 見かけ上 チェックなし 💡 ジェネリクスは「型安全」と「再利用性」を両立できる唯一のアプローチ

型の境界(バウンデッドタイプ)

ジェネリクスには「型パラメータに制約をかける」機能もあります。たとえば「数値型なら何でも受け付けるが、文字列は受け付けない」という制限が可能です。

// TypeScriptの例
// T は number か string のどちらか(共用体型)
function identity<T extends number | string>(value: T): T {
  return value;
}

// Tは Comparable インターフェースを実装した型のみ(Javaの例)
// <T extends Comparable<T>>

関連する規格・RFC

※ ジェネリクスはプログラミング言語仕様の範疇であり、IETFのRFCは存在しません。各言語の仕様書を参照してください。

仕様・JSR内容
JSR-14 (Java Generics)Javaへのジェネリクス導入仕様(Java 5)
ECMA-262 (TypeScript基盤)TypeScriptが乗っかるECMAScript標準
ISO/IEC 14882 (C++)C++のテンプレート機能を含む国際標準

関連用語