0

カスタム オブジェクトの優先キューを実装しています。カスタム オブジェクト クラスは以下のようになります。T は単純に messageId に関連付けられたペイロードであるジェネリック クラスとして実装することをお勧めしますか?

public class PriQMsgPayload <T> implements Comparable<PriQMsgPayload<T>>{


    private Integer mMsgNum;
    private T ExtraDataForMsg = null;

    public PriQMsgPayload(T extra, PluginConfig.PriQMessage msg)
    {
        mMsgNum= msg;
        ExtraDataForMsg = extra;
    }

    @Override
    public int compareTo(PriQMsgPayload<T> another) {
        return mMsgNum.compareTo(another.mMsgNum);
    }
}

私の疑問: 以下のケースでは、最初に Integer に特化した P1 を挿入し、MyClass に特化した別のオブジェクト P2 を挿入すると、コンパレーターは混乱しませんか?

PriQMsgPayload<Integer> P1 = new PriQMsgPayload<Integer>(2, 1);
PriQMsgPayload<MyClass> P2 = new PriQMsgPayload<MyClass>(new MyClass(), 2);
4

3 に答える 3

1

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 ライブラリの設計者がなぜこのようにしなかったのか、私にはわかりません。

于 2012-10-10T09:53:32.713 に答える
1

意味がないと思います。問題は、オブジェクトをキューに入れようとしたときに発生します。これらの両方を含めることができる、キューが持つことができる完全にクックされた型はありません!

検討:

PriorityQueue queue; // works, but is raw
PriorityQueue<PriQMsgPayload> queue; // works, but is partially raw
PriorityQueue<PriQMsgPayload<Object>> queue; // won't accept either object

それらをこのタイプのキューに入れることができます(最初はできないと言っていましたが、@newacctが親切に修正してくれました)

PriorityQueue<PriQMsgPayload<?>> queue; // won't accept either object

しかし、それには、どんな種類の余分なデータがあるかについての型情報を捨てる必要があります。

両方のオブジェクトを追加できるキュー タイプはいずれも、余分なデータのタイプを保持しません。つまり、オブジェクトを再び取り出したときに、すべての型情報が失われることになります。PriQMsgPayload<Integer>オブジェクトをではなくとして安全に抽出するコードを書く方法はありませんPriQMsgPayload<MyClass>

于 2012-10-09T08:03:07.327 に答える
0

正確にはどういう意味ですか?

compareTo()引数としてP1渡すことを呼び出すことはできませんP2(またはその逆)。P1.compareTo()を期待しているため、コンパイルエラーが発生します。PriQMsgPayload<Integer>したがって、を渡すことはできませんPriQMsgPayload<MyClass>

于 2012-10-09T07:54:42.037 に答える