この記事は、多くの記事やブログを読み、ソースをまとめ、「Javaで考える」参照から導出され
序文
Javaのジェネリックは、すべてのみんなを使用しているが、何その基礎となる実装方法があることは、ジェネリック医薬品によって引き起こされる問題を解決する方法、それは、なぜ実現する必要があり、このような実装のどのような利点と欠点。好奇心で、私はここにあなたと一緒に探索する予備調査の情報にアクセスすることができます。
typeパラメータ
JAVAは、ジェネリックを知っていて、使用する方法について理解して学びました。クラスのクラス名:クラスで
{}、方法において:公共 ボイドメソッド名(T x)から{}。このようなパラメータのジェネリック型に実装され、多様なタイプ機能するよう、渡すことができます。
5例に分け、特定:
- T型のメンバ変数であります
- Tは、共通として型パラメータの型変数(メンバ変数またはローカル変数かどうか)です
Class<T
>List<T>
。 - 方法Tは例外をスローしている(要件
<T extends Exception>
) - 戻り値は、Tの方法であります
- 法Tはパラメータであり、
1.1ジェネリックを達成します
JAVAは、一般的なコンパイラの実装、それが作られ、下位互換性を維持するために、java1.5のジェネリック妥協の後に登場しているため、実装の消去方法に基づいています。
別に他の場所で記録されたバイトコードにコンパイル時に消去されているJAVAパラメータと呼ばれているファイルの種類を、消去します。そして、親クラスの型パラメータによって元の位置を交換してください。
パラメータタイププレースホルダは、次の規則を消去し、Tとし:
<T>
消去がなった後Obecjt
<? extends A>
消去がなった後A
<? super A>
消去がなった後Object
この規則は、バインドされた予約されたアッパーと呼ばれ、
使用時にはJAVAをキャストすることにより、コンパイラ型パラメータを消去した後、適切な型のパラメータを保証します。例えば:タイプAの着信クラスパラメータT、すべてのクラスの強力な回転のためのコードタイプパラメータTプラス(A)におけるコンパイラリターン(スロー)。
栗の場合:
ArrayList<String> list = new ArrayList<String>();
list.add("123");
String b = list.get(0);
コンパイルした後になります
ArrayList list = new ArrayList();//没有参数即默认为Object
list.add("123");
String b = (String) list.get(0);
橋を形成する方法およびクラス型パラメータとサブクラスにおける多型ことを保証します。
以下の公式の説明を特に参照します
- 型パラメータが無制限であれば、その境界またはオブジェクトとジェネリック型のすべての型パラメータを交換してください。生成バイトコードは、従って、唯一の一般クラス、インタフェース、及び方法を含んでいます。
- 型の安全性を維持するために、必要に応じて挿入タイプがキャスト。
- 拡張されたジェネリック型で多型を維持するためのブリッジメソッドを生成します。
二 通配符?
パラメータの型を持つクラス内では、コードがまだ消去親クラスのパラメータの型で処理すること。しかし、このメカニズムのジェネリックに問題がある消去することは、インバータと共分散せず、同じです。
2.1インバータと共変
オンライン共分散と多くの説明がありますが、私はいくつかのプログラミング言語の公式な説明を参照するの比較的広い定義を与える、漠然としたようです。共変タイプを使用することができる意味(具体的)誘導体の種類よりも、元の請求項大きな程度、インバータを使用することができる構造型宣言された型の元のレベルよりも小さい(少ない特定)を意味します。
例えば:
Object obj = new String("123");
これは共分散であり、より具体的な(サブクラス)オブジェクトタイプに文字列は、最初のタイプ(親)の広い定義に割り当てられました。
JAVAは、サブクラスに割り当てられた親クラス、自然なJavaはインバータをサポートしていないことはできませ。
多くのオンラインジェネリックJAVAボーエンはインバータ、そこに私は同意しない、それはインバータの単なるシミュレーションであると述べ、それはインバータ部の特性であり、インバータのように見える、テキストは、詳細な分析の後に与えられます
2.2 Javaのインバータと共分散
Javaでは、
List<Integer> b = new ArrayList<Integer>()
List<NumFber> a = b;
これは、コンパイラによってチェックされません。一般的なように、セキュリティの種類を損なうそうする:それは非常に良い理由を持ってすることはできません。それが可能な場合はList<Integer>
割り当てられましたList<Number>
。その後、次のコードは、非許可するInteger
にコンテンツをList<Integer>
:
List<Integer> b = new ArrayList<Integer>();
List<Number> a = b; // illegal
a.add(new Float(3.1415));
なぜならa
、それがあるList<Number>
ので、追加して、Float
完全に実行可能なように見えますが。しかし場合はa
、実際にList<Integer>
、これは中意味合い弱体化させるだろうb
定義された型宣言を-それは、ジェネリック型は関連付けを変更することはできません理由である、整数のリストです。しかし、このようになっていジェネリック医薬品は、多型の拡大を失います。
2.3ワイルドカードソリューションの共変
ワイルドカード追加して、Javaの公式?
問題のジェネリックの共変を解決するために。これは、コンパイルされます:
List<Integer> b = new ArrayList<Integer>();
List<? extends Number> a = b;
読み取ることができるa
有するから、クラスのセットを統合データとして抽出の時間ラインの処理。これは、リヒターの置換原則に沿ったものでもありましたNumber
List
a
Number
しかし、コンパイラはあなたがしたい禁じますInteger
置く、つまり、a.add(new Integer(1))//illegal
あなたの文があるため、それは、また、非常に合理的であるa
何定義されていなかったa
含まれていたコンクリートNumber
のサブカテゴリーを、したがって、ジェネリック医薬品の安全性を確保するために、任意の変数を追加することはできません。
解決するa
方法は、オブジェクトを追加することも非常に簡単です
List<Object> b = new ArrayList<Object>();
List<? super Number> a = b;
a
いくつかの一種であるNumber
親クラスList
、コレクションされArrayList<Object>
割り当てられa
、妥当であるObject
確かにNumber
親クラス。これは、リヒターの置換原則に沿ったものでもあります
(ほとんどのオンラインボーエンは、これがインバータであることを言ったが、インバータの正式な定義について考え、JAVA、それは次のように理解することができます。クラスはT
クラスでS
サブクラス、およびクラスがA<T>
クラスであるA<S>
親クラスよく見るList<? super Number>
とList<Object>
の関係、ここT
でNumber
、とS
あるObject
が、List<? super Number>
論理的な観点から、本当にList<Object>
文字通り場合、そのサブクラスList<? super Number>
であるNumber
親クラスのコレクション、準備金を消去するに従って上限の方法のように消去する必要があります他に割り当てられたが。私は情報へのGoogleのアクセスダウンそれを疑うインバータのいずれかに存在しない、JAVA、一般的な英語についての情報)は、インバータのこの部分ではありませんList<Object>
List<Object>
List<Object>