5

私は C++ の経験が少しある Java 初心者であり、次の行に沿って Java でセットのセットを作成しようとしています (C++ で行うことと同様):

Set< Set< String > > collection = new TreeSet< Set< String > >();
Set< String > entry =  new TreeSet< String >();
collection.add( entry );

これは正常にビルドされますが、プログラムが実行されるとjava.util.TreeSet cannot be cast to java.lang.Comparable例外がスローされます。

ホイールを再実装せずに、Java でセットのセットを作成するにはどうすればよいでしょうか?

また、壊れたコード (型の不一致など) をコンパイルできるようにする Java との取り決めは何ですか?

フィードバックをお寄せいただきありがとうございます。

4

3 に答える 3

7

の契約ではTreeSet、すべてのエントリComparableComparator. (これが、コンパイル時エラーが表示されなかった理由でもあります。エントリはComparable、明示的な が存在しない場合にのみキャストされComparatorます。)

ジェネリックとは関係ありません。それ自体の実装に由来しTreeSetます。バイナリ ツリーであるため、何らかの方法でエントリを順序付けできる場合にのみ意味があります。

特定の問題についてもう少し教えていただければ、必要な正確なデータ構造を見つけるのに役立つ可能性がありますが、一般に、セット内の要素の順序を気にしない場合は、 aHashSetが使用されます。繰り返しになりますが、一般的に、Setsの aSetはしばしばずさんなデザインの兆候です。

于 2012-04-14T19:13:05.333 に答える
2

TreeSetオブジェクトをコレクションに追加する場合、そのオブジェクトの型はComparableインターフェイスを実装する必要がありますが、それTreeSet自体は実装していません。Comparatorまたは、別のコンストラクターを使用して TreeSet を作成することにより、 を提供できます。

TreeSetこれは定義上、順序付きコレクションであり、要素の順序付けは必要ないように思われるため、この特定のシナリオでa を使用するのはあまり意味がありません。HashSet代わりにa を試すことができます。

さらに、2番目の質問に答えるために、このエラーは実行時にのみ表示されます。これは、ポリモーフィックな動作を悪用しているためです。つまりSet、実行時に実際には にバインドされている に追加していますTreeSet。この情報は、コンパイル時にはわかりません。

于 2012-04-14T19:15:38.093 に答える
0

問題は、カスタムコンパレータを受け入れるか、自然な順序を使用できる必要があるため、ジェネリックスの観点からは完全に「タイプセーフ」でないことですTreeSet

TreeSet自然な順序付けのみを使用した場合、それはとして宣言でき、TreeSet<E extends Comparable<? super E>>タイプセーフになります。それ自体と比較できないタイプは、パラメーターとして使用できません。一方、常にコンパレータを使用している場合は、タイプセーフでもあります。

TreeSetしかし、現在の設計方法では、コンパレータなしで(したがって、自然な順序を使用して)、それ自体に匹敵しない要素タイプでを作成できます。これを強制するためのコンパイル時チェックはありません。失敗は実行時にのみ通知されます。

実際にTreeSet修正できる方法があります。自然な順序付けとカスタムコンパレータの両方をサポートし、タイプセーフになります。

  • カスタムコンパレータを受け入れるコンストラクタを持っている

  • 自然な順序付けの場合のコンストラクターはありません。TreeSet代わりに、自然な順序を使用するを作成するファクトリメソッドを用意してください。ファクトリメソッドは、ジェネリック型をバインドすることができます。これ<E extends Comparable<? super E>>には、型がそれ自体と同等である必要があります。

Javaライブラリの設計者がなぜこのようにしないのかわかりません。

于 2012-04-15T02:22:15.613 に答える