21

Java ArrayList<T>(およびおそらく他の多くのクラス)の内部で起こることは、オブジェクトが書き込まObject[] array = new Object[n];れる内部があるということです。T要素がそこから読み取られるたびに、キャストreturn (T) array[i];が実行されます。したがって、すべての読み取りにキャストします。

なぜこれが行われるのだろうか。私には、彼らは不必要なキャストをしているように見えます。T[] array = (T[]) new Object[n];を作成してからreturn array[i];キャストせずに作成する方が論理的で、少し速くなりませんか?これは、アレイの作成ごとに1つのキャストのみであり、通常、読み取りの数よりはるかに少なくなります。

なぜ彼らの方法が好まれるのですか?なぜ私の考えが厳密に良くないのかわかりませんか?

4

4 に答える 4

18

それよりも複雑です。ジェネリックはバイトコードで消去され、の消去はT[]ですObject[]。同様に、の戻り値はにget()なりObjectます。型システムの整合性を維持するために、クラスが実際に使用されるときにチェックされたキャストが挿入されます。

Integer i = list.get(0);

に消去されます

Integer i = (Integer) list.get(0);

その場合、ArrayList内の型チェックは冗長です。ただし、とは両方ともチェックされていないキャストであり、実行時のオーバーヘッドが発生しないため、これは実際には重要で(T)(T[])ありません。

次のようなチェック済みのArrayListを作成できます。

T[] array = Array.newInstance(tClass, n);

これにより、ヒープの汚染を防ぐことができますが、タイプチェックが冗長になります(コードの呼び出しで合成キャストを抑制することはできません)。また、呼び出し元がArrayListに要素型のクラスオブジェクトを提供する必要があります。これにより、APIが乱雑になり、ジェネリックコードでの使用が困難になります。

編集:なぜジェネリックアレイの作成が禁止されているのですか?

1つの問題は、ジェネリックがチェックされていないのに、配列がチェックされていることです。あれは:

Object[] array = new String[1];
array[0] = 1; // throws ArrayStoreException

ArrayList list = new ArrayList<String>();
list.add(1); // causes heap pollution

したがって、配列のコンポーネントタイプが重要になります。これが、Java言語の設計者が、使用するコンポーネントタイプについて明示的に要求する理由だと思います。

于 2012-09-11T09:00:28.537 に答える
4

要素がそこから読み取られるたびに、キャストreturn (T) array[i];が実行されます。したがって、すべての読み取りにキャストします。

Genericはコンパイル時のチェックです。実行時には、代わりにタイプTextendsが使用されます。この場合、T暗黙的extends Objectに実行時に持っているものが効果的になります。

return (Object) array[i];

また

return array[i];

ただ作成する方が論理的で少し速いのではないでしょうか

T[] array = (T[]) new Object[n]

あまり。再び実行時にこれは次のようになります

Object[] array = (Object[]) new Object[n];

また

Object[] array = new Object[n];

あなたが本当に釣りをしているのは

T[] array = new T[n];

ただし、これはコンパイルされません。これは主に、実行時にTが不明であるためです。

あなたにできることは

private final Class<T> tClass; // must be passed in the constructor

T[] array = (T[]) Array.newInstance(tClass, n);

そうして初めて、配列は実際に期待される型になります。これにより、読み取りが高速化される可能性がありますが、書き込みが犠牲になります。主な利点は、フェイルファストチェックです。つまり、コレクションが破損していることを検出して例外をスローするのを待つのではなく、コレクションの破損を停止します。

于 2012-09-11T09:04:42.360 に答える
2

パフォーマンスや型の安全性ではなく、コードスタイルの問題だと思います(バッキング配列はプライベートであるため)

java 5ArrayListは、E[]配列で提案した方法で実装されました。ソースコードを見ると、7つの(E [])キャストが含まれていることがわかります。java 6から、配列ArrayListを使用するように変更され、Object[]3(E)キャストのみになりました。

于 2012-09-11T09:22:07.580 に答える
-1

配列もオブジェクトです。ここT[] array = (T[]) new Object[n]では、配列内の要素ではなく、(T [])オブジェクトタイプのみをキャストします。

于 2012-09-11T08:55:09.917 に答える