コンピューティングでは、具体化とは、型の明示的な表現、つまり実行時型情報を意味するようになりました。
Oracleチュートリアル 言う、
再定義可能な型とは、実行時に型情報が完全に利用できる型です。これには、プリミティブ、非ジェネリック型、raw型、およびバインドされていないワイルドカードの呼び出しが含まれます。
再認識不可能な型とは、コンパイル時に型消去によって情報が削除された型です。つまり、無制限のワイルドカードとして定義されていないジェネリック型の呼び出しです。
次のいずれかである場合、タイプは再定義可能です:
- プリミティブ型(
int
など)//理解済み- パラメータ化されていないクラスまたはインターフェイスタイプ(
Number
、String
、Runnable
など)//理由- すべての型引数が無制限のワイルドカードであるパラメーター化された型(
List<?>
、ArrayList<?>
、またはMap<?, ?>
など)//理由- 生の型(
List
、ArrayList
、Map
など)//理由- コンポーネントタイプが再定義可能な配列(
int[]
、Number[]
、List<?>[]
、List[]
、int[][]
など)//理由
タイプが次のいずれかである場合、タイプは再定義できません:
- 型変数(
T
など)//理由- 実際のパラメーター(
List<Number>
、ArrayList<String>
、またはMap<String, Integer>
など)を持つパラメーター化されたタイプ//理由- 境界のあるパラメーター化されたタイプ(
List<? extends Number>
やComparable<? super String>
など)//理由
なぜ2,3,4,5が再利用可能で、6,7,8が再利用不可能なのですか?
Sun/Oracleによると 理由は、必要性(コンパイル時の型チェックで十分)、コードサイズ(STLのようなコードの膨張を回避)、パフォーマンス(コンパイル時にすでに実行された実行時の型チェックを回避)の組み合わせです。 )::
型消去により、パラメーター化された型に対して新しいクラスが作成されないことが保証されます。その結果、ジェネリックは実行時のオーバーヘッドが発生しません。
つまり、1〜5はコードで指定されたものと同じ型のままであるため、型情報が失われたり消去されたりすることはありませんが、6〜8はコンパイル中に型情報(<>の間のもの)が失われるため、再利用可能です。実行時にアクセスされません。
この2つの用語の意味を理解してください。
Reizableは、実行時に型が完全に使用可能であることを意味しますJavaコンパイラは型消去のプロセスを必要としません。
Non-ReizableはJava型が完全に利用できないため、コンパイラには型消去プロセスが必要であることを意味します。
次のいずれかである場合、タイプは再定義可能です:
1。プリミティブ型(intなど):
ここで、intを参照として記述または使用する場合、コンパイラにはintの型を識別するためのプロセスが必要だと思いますか? intはintであるため、いいえ。すべてのプリミティブ型で同じです。
2。パラメータ化されていないクラスまたはインターフェイスタイプ(Number、String、Runnableなど)
前の回答で言ったのと同じ回答で、コンパイラはNumber、String、またはRunnableの型消去を必要としません。
。すべての型引数が無制限のワイルドカードであるパラメーター化された型(List <?>、ArrayList <?>、Map <?、?>など)
制限のないワイルドカードはすべて、再定義可能なタイプの定義ですでに言及されているため、再有効化可能なタイプとして受け入れられます。現在、API開発者が、それを再定義可能なタイプと見なす理由は異なります。
4。生の型(List、ArrayList、Mapなど)::
最初の質問と同じ答え
5。コンポーネントタイプが再定義可能な配列(int []、Number []、List <?> []、List []、int [] []など)::
最初の質問と同じ答え
次のいずれかである場合、タイプは再定義できません:
6。型変数(Tなど):
JavaはTの型を識別できないため、コンパイラは型を識別するために型消去が必要です。
7。実際のパラメーター(List <Number>、ArrayList <String>、Map <String、Integer>など)を持つパラメーター化された型:
ここで、すべての型はジェネリック型です。実行時にコンパイラはList as List ...を参照してください。したがって、Non-refiableの定義に従って、これらのコレクションはすべて再利用不可能と見なされます。
8。境界のあるパラメーター化された型(List <?extendsNumber>やComparable <?super String>など)
前の答えと同じ答え
あなたはグーグルに同じ質問をすることができます:
再利用可能なタイプ
ジェネリックスを使用すると、多くの場合、コンパイル時の型情報が失われます。実行時に、プログラムが参照について知っているのは、ある種のオブジェクトへの参照であることがよくあります。実行時にすべてのタイプ情報もわかっている場合、そのタイプは再検証可能と呼ばれます。おそらくいつかジェネリックが再設計され、すべてのタイプが再設計可能になるでしょう。
再定義可能な型とは、実行時に型情報が完全に利用できる型です。これには、プリミティブ、非ジェネリック型、raw型、およびバインドされていないワイルドカードの呼び出しが含まれます。
再認識不可能な型とは、コンパイル時に型消去によって情報が削除された型のことです。無制限のワイルドカードとして定義されていないジェネリック型の呼び出しです。再利用不可能なタイプでは、実行時にすべての情報を利用できるわけではありません。再利用不可能なタイプの例は、List <String>およびList <Number>です。 JVMは、実行時にこれらのタイプの違いを区別できません。ジェネリックスの制限に示されているように、再定義不可能な型を使用できない特定の状況があります。たとえば、式のインスタンスで、または配列の要素として。
Javaは元々バージョン1.1でリフレクションを実装していました。
ジェネリッククラスはバージョン5.0で導入されました。
ジェネリックスを導入する際、下位互換性の理由から、ジェネリック型の情報は実行時に消去されることが決定されました。これにより、ジェネリック以前に記述されたコードを、ジェネリックベースのコードで変更せずに操作できるようになりました。
たとえば、List[Integer32]
はコンパイラによってInteger32[]
に変換されます。すべての型チェックはコンパイル時に実行され、何かが欠落していると、実行時エラーが生成されます。
この実装の詳細は、ジェネリックが具体化されていないことを意味し(VMにそれらの特定の実装はありません)、したがって、ジェネリック型を反映しようとすると、返される情報は基になる型の情報になります。これが有利であるもう1つの理由は、具体化された型の実装が使用されるたびにVMによって発行される必要がないためです(たとえば、c#では、汎用型を使用する場合は常に実際の実装は、実行時にVMとリフレクションメタデータによって生成されるため、新しいタイプを生成する必要があるたびにパフォーマンスが低下します)。
単なる知識に基づく推測ですが、これを理解するための鍵は、Javaは強く型付けされた言語であり、コンパイルプロセスの一部として型参照を検証する一方で、多くの場合、型情報であることを認識することだと思います。ロジックを実行するのに実際には必要ありません。その場合、生成されたバイトコードは、オブジェクトのインスタンスで動作していることを認識していても、型を認識していない可能性があります。強い型付けを使用しない言語では、これが特に意味があります。 Javaバイトコードとして生成されます。したがって、オブジェクトタイプが削除された場合、インスタンスは再利用できなくなります。