PriQMsgPayload<Integer>
まあ、理想的には、 aと aを比較することはできないはずですPriQMsgPayload<String>
-- なぜなら、 a は をPriQMsgPayload<Integer>
実装Comparable<PriQMsgPayload<Integer>>
しているため、そのcompareTo
メソッドは をPriQMsgPayload<Integer>
受け取るので、 を期待しないからPriQMsgPayload<String>
です。
コンパイル時と実行時の両方でこれを行おうとするとどうなるかは、プライオリティ キュー クラスの宣言方法とその動作方法によって異なります。使用しているプライオリティ キューの実装を教えてくれませんでした。
次のように宣言された一般的な優先度キュー クラスがあるとします。
class MyPriorityQueue<E extends Comparable<? super E>> { ... }
つまり、その型パラメーターがそれ自体と同等である必要があります。PriQMsgPayload<Integer>
その場合、 と の両方を挿入できる優先キューを宣言することは不可能PriQMsgPayload<String>
です。たとえば、 は境界を満たさないため、MyPriorityQueue<PriQMsgPayload<?>>
許可されないためです。PriQMsgPayload<?>
を使用している場合java.util.PriorityQueue
、問題はPriorityQueue
クラス (TreeSet
およびTreeMap
など) がタイプ セーフではないことです。を作成しnew PriorityQueue<Object>()
、それにどんな種類のオブジェクト (完全に比較できないもの) を挿入しても、コンパイル時に何もキャッチせず、実行時にのみ失敗します (または、オブジェクトのタイプによっては、たまたま機能する可能性があります)。 )。
この場合、実行時に何が起こるでしょうか? さて、型消去の後、実行時に、クラスはこれと同等です:
public class PriQMsgPayload implements Comparable {
// ....
public int compareTo(Object another) {
return compareTo((PriQMsgPayload)another);
}
public int compareTo(PriQMsgPayload another) {
return mMsgNum.compareTo(another.mMsgNum);
}
}
単純に整数を比較するため、この場合、実行時に問題なく動作します。
PriorityQueue
タイプセーフではないのはなぜですか? このクラスを見ると、次の 2 つの方法のいずれかで使用するように設計されています: custom を提供するComparator
か、オブジェクトの「自然な順序付け」を使用します。後者の場合、それ自体に匹敵するものを提供することになっていますが、これはコンパイル時に強制されません。任意の型で機能するカスタム コンパレータ (方法 1) と共に使用できるため、MyPriorityQueue
上記のように、クラスの型パラメーターに境界を設定することはできません。
実際には、PriorityQueue
タイプ セーフにする方法があり、カスタム コンパレータと自然な順序付けモードの両方をサポートできます。自然順序付けを使用するコンストラクターを単純に削除し (コンパレーターを使用するコンストラクターはタイプ セーフであるため残します)、代わりにそれらをファクトリ メソッドに置き換えます。たとえば、コンストラクター
PriorityQueue(int initialCapacity)
ファクトリメソッドに置き換えることができます
public static <T extends Comparable<? super T>> PriorityQueue<T> construstUsingNaturalOrdering(int initialCapacity) {
return new PriorityQueue<T>(initialCapacity, new NaturalOrderingComparator<T>());
}
このように、ファクトリ メソッドにバインドされたジェネリックにより、自然順序付けの優先度キューは、それ自体と比較可能な型に対してのみ構築できることが保証されます。Java ライブラリの設計者がなぜこのようにしなかったのか、私にはわかりません。