web-dev-qa-db-ja.com

Reified Genericsとは何ですか? Type Erasureの問題をどのように解決し、大きな変更なしでは追加できないのはなぜですか?

私は Neal Gafter's というテーマのブログを読みましたが、いくつかの点についてはまだわかりません。

Java、JVM、および既存のコレクションAPIの現在の状態を考慮して、型情報を保持するコレクションAPIの実装を作成できないのはなぜですか? Javaの将来のバージョンでは、後方互換性が維持される方法で、これらは既存の実装を置き換えることができませんでしたか?

例として:

List<T> list = REIList<T>(T.Class);

REIListは次のようなものです。

public REIList<T>() implements List {
  private Object o;
  private Class klass;

  public REIList(Object o) {
    this.o = o;
    klass = o.getClass();
  }
... the rest of the list implementation ...

また、メソッドはObject oとClass klassを使用して型情報を取得します。

JVM実装の変更だけでなく、汎用クラス情報を保持するには言語の変更が必要なのはなぜですか?

私は何を理解していないのですか?

66
sal

全体のポイントは、具体化されたジェネリックはコンパイラで型情報を保持することをサポートしているのに対し、型消去されたジェネリックはサポートしていないということです。知る限り、そもそも型の消去を行うことの全体的なポイントは、後方互換性を有効にすることでした(たとえば、より低いバージョンのJVMはまだ汎用クラスを理解できます)。

上記のように、実装に型情報を明示的に追加できますが、リストを使用するたびに追加のコードが必要になり、私の意見ではかなり面倒です。また、この場合、自分でチェックを追加しない限り、すべてのリストメソッドの実行時型チェックはまだありませんが、具象ジェネリックは実行時型を保証します。

34
ghempton

Java開発者の大多数の信念に反して、非常に制限された方法にもかかわらず、実行時にコンパイル時の型情報を保持し、この情報を取得することが可能です。つまり、Javaは、非常に制限された方法で具体化されたジェネリックを提供します

型消去について

コンパイル時に、コンパイラは完全な型情報を利用できますが、この情報は意図的に削除されます一般type erasureとして知られるプロセスで、バイナリコードが生成されるとき=。これは、互換性の問題によりこのように行われます。言語設計者の意図は、プラットフォームのバージョン間で完全なソースコードの互換性と完全なバイナリコードの互換性を提供することでした。異なる方法で実装された場合、プラットフォームの新しいバージョンに移行するときにレガシーアプリケーションを再コンパイルする必要があります。それが行われた方法、すべてのメソッドシグネチャは保持され(ソースコードの互換性)、何も再コンパイルする必要はありません(バイナリ互換性)。

Javaの具象ジェネリックについて

コンパイル時の型情報を保持する必要がある場合は、匿名クラスを使用する必要があります。重要な点は、匿名クラスの非常に特殊なケースでは、実行時に完全なコンパイル時の型情報を取得することです。つまり、具体化されたジェネリックです。

このテーマに関する記事を書きました。

http://rgomes-info.blogspot.co.uk/2013/12/using-typetokens-to-retrieve-generic.html

この記事では、ユーザーがこの手法にどのように反応したかを説明します。一言で言えば、これはあいまいな主題であり、テクニック(または必要に応じてパターン)は、大多数のJava開発者にとって無関係です。

サンプルコード

上記の記事には、アイデアを実行するソースコードへのリンクがあります。

19
Richard Gomes

IIRC(およびリンクに基づく)Javaジェネリックは、Objectコレクションを使用して前後にキャストする既存の手法の単なる構文上の砂糖です。 Javaジェネリックを使用すると、コンパイラがcompile-time型安全性を維持していることを確認するためのチェックを行うことができるため、より安全で簡単です。ただし、実行時間はまったく別の問題です。

一方、.NETジェネリックは実際に新しい型を作成します-C#のList<String>List<Int>とは異なる型です。 Javaの場合、これらは同じもの-List<Object>です。これは、それぞれを持っている場合、実行時にそれらを見て、それらが何として宣言されているかを見ることができないことを意味します-現在のものだけです。

具象化されたジェネリックはそれを変更し、Java開発者に現在.NETに存在するのと同じ機能を提供します。

12
Harper Shelby

私はこの問題の専門家ではありませんが、理解したように、型情報はコンパイル時に失われます。 C++とは異なり、Javaはテンプレートシステムを使用しません。型安全性は完全にコンパイラによって実現されます。実行時、リストは実際には常にリストです。

したがって、型情報がJVMで利用できないという事実のために、言語仕様の変更が必要であるというのが私の見解です存在しないため

4
n3rd