回答:
Javaのジェネリックスは完全にコンパイル時の構造です-コンパイラはすべてのジェネリック使用を適切な型へのキャストに変換します。これは、以前のJVMランタイムとの下位互換性を維持するためです。
この:
List<ClassA> list = new ArrayList<ClassA>();
list.add(new ClassA());
ClassA a = list.get(0);
(大体)に変わります:
List list = new ArrayList();
list.add(new ClassA());
ClassA a = (ClassA)list.get(0);
したがって、ジェネリックスとして使用されるものはすべてObjectに変換可能である必要があり(この例でget(0)
はを返しますObject
)、プリミティブ型は変換できません。そのため、ジェネリックでは使用できません。
Javaでは、ジェネリックは、少なくとも一部は...言語が設計されてから数年後に言語に追加されたため、ジェネリックと同じように機能します1。言語設計者は、既存の言語およびJavaクラスライブラリとの下位互換性のある設計を考え出す必要があるため、ジェネリックスのオプションに制約を受けていました。
その他のプログラミング言語(C ++、C#、Adaなど)では、プリミティブ型をジェネリックスのパラメーター型として使用できます。ただし、これを行うと、そのような言語のジェネリック(またはテンプレートタイプ)の実装では、通常、各タイプのパラメーター化に対してジェネリックタイプの個別のコピーが生成されます。
1-ジェネリックがJava 1.0に含まれなかった理由は、時間のプレッシャーが原因でした。彼らは、Webブラウザーによってもたらされる新しい市場機会を満たすために、Java言語を迅速にリリースする必要があると感じていました。ジェームズ・ゴスリング氏は、ジェネリック医薬品に時間があれば、ジェネリック医薬品を含めたいと述べた。これが起こった場合、Java言語はどのように見えたでしょうか。
Javaでは、ジェネリックは、下位互換性のために「型消去」を使用して実装されます。すべてのジェネリック型は、実行時にObjectに変換されます。例えば、
public class Container<T> {
private T data;
public T getData() {
return data;
}
}
実行時に次のように表示されます。
public class Container {
private Object data;
public Object getData() {
return data;
}
}
コンパイラは、型の安全性を確保するために適切なキャストを提供する責任があります。
Container<Integer> val = new Container<Integer>();
Integer data = val.getData()
となります
Container val = new Container();
Integer data = (Integer) val.getData()
ここで問題は、なぜ「オブジェクト」が実行時にタイプとして選択されるのかということです。
Answer is Objectはすべてのオブジェクトのスーパークラスであり、ユーザー定義のオブジェクトを表すことができます。
すべてのプリミティブは「Object」を継承しないため、ジェネリック型として使用することはできません。
参考:プロジェクトValhallaは上記の問題に対処しようとしています。
コレクションは、から派生するタイプを必要とするように定義されていますjava.lang.Object
。ベースタイプは単にそれをしません。
あたりとしてJavaドキュメント、ジェネリック型の変数は、参照型ではなく、プリミティブ型でインスタンス化することができます。
これは、Java 10のProject Valhallaで提供される予定です。
でブライアン・ゲッツの上の紙専門の州
ジェネリックがプリミティブでサポートされなかった理由については、優れた説明があります。また、Javaの将来のリリースでどのように実装されるか。
すべての参照インスタンス化に対して1つのクラスを生成し、プリミティブインスタンス化をサポートしない、Javaの現在の消去済み実装。(これは同種の変換であり、Javaのジェネリックが参照型にのみ及ぶことができるという制限は、参照型とプリミティブ型の操作に異なるバイトコードを使用するJVMのバイトコードセットに関する同種の変換の制限によるものです。)ただし、Javaで消去されたジェネリックは、動作パラメトリック性(ジェネリックメソッド)とデータパラメトリック性(ジェネリック型の生およびワイルドカードのインスタンス化)の両方を提供します。
...
同種の変換戦略が選択されました。この場合、ジェネリック型の変数は、バイトコードに組み込まれるときに境界まで消去されます。これは、クラスがジェネリックであるかどうかにかかわらず、同じ名前で単一のクラスにコンパイルされ、メンバーシグネチャが同じであることを意味します。型の安全性はコンパイル時に検証され、ランタイムはジェネリック型システムによって制限されません。次に、Objectは利用可能な最も一般的な型であり、プリミティブ型には拡張されないため、ジェネリックは参照型に対してのみ機能するという制限が課されました。