6

私は少し混乱しています。Javadoc の警告。PriorityQueue が必要なものかどうかさえわかりません...

私の状況は次のとおりです。整数のタイムスタンプとその他のフィールドを持つクラス Event があります。これらのイベントを挿入でき、イベントをタイムスタンプでソートできるデータ構造を探しています。異なるイベントが同じタイムスタンプを持つ可能性があるため、正しく理解できれば、compareTo と equals は矛盾します。

私の最初のアプローチは、Event に Comparable を実装させ、compareTo を次のように提供することでした。}

これをどのように解決すればよいのかわかりません。カスタム Comparator を作成することを考えましたが、奇妙な動作に関する同じ警告が Comparator の javadoc にも表示されます。イベントの複数の等しいインスタンスを挿入したくありません。それらをタイムスタンプでソートしたいだけです。

よろしくお願いします:)

編集:
イベントをタイムスタンプでソートしたいだけです。2 つの異なるイベントのタイムスタンプが同じである可能性は十分にあります。したがって、compareTo は 0 を返します。これは、タイムスタンプが同じであり、並べ替えの目的で等しいためです。しかし、これらは異なるイベントであるため、equals() は true を返しません。
よくわかりませんが、PriorityQueue を使用するのが適切です。SortedSet を見ましたが、compareTo と equals の一貫性について同じ警告がありました。
多分私はこれに間違った角度から取り組んでいます、わかりません...

4

3 に答える 3

5

異なるイベントが同じタイムスタンプを持つことができます

そして、イベントをタイムスタンプでソートします

後者の要件はやや不明確です。コレクションのイテレータはインスタンスをソート順に返す必要がありますか? poll()それとも、ループ内の場合、コレクションは以前の内容をソートされた順序で返す必要がありますか?

iterator()要素を順番に返す

の場合はそうではありませんPriorityQueue。を使用することもできますがSortedSet、並べ替え順序が equals と一致している必要があります。正しくお気づきのように、これは達成できません。私の知る限り、Collection一部の要素が等しいと見なされる並べ替え順序のために、その要素を並べ替えた順序で保持する JDK はありません。ただし、配列またはを使用して、またはをArrayList使用して変更後に手動で並べ替えることができます。コレクションがめったに変更されない場合、これが私が選択するアプローチです。頻繁に変更される場合は、JDK の先を見るか、データ構造を自分で実装する必要があります。Arrays.sortCollection.sort

poll()ソートされた順序で要素を返します

それが優先キューの良いところです。は(または の実装) が equals と一致する必要PriorityQueueはありません。そのJavaDocは明確に書いています:ComparatorComparable

このキューの先頭は、指定された順序に関して最小の要素です。複数の要素が最小値で結合されている場合、ヘッドはそれらの要素の 1 つです。結合は任意に解除されます。

さらに、PriorityQueueJDK 6での の実装は、とequalsを実装するためだけに使用され、どちらもコンパレータをまったく使用しません。したがって、 equals との一貫性が this にとって重要になる方法は実際にはありません。indexOf(E)contains(Object)remove(Object)Collection

比較可能対比較

equals との一貫性に関する限り、 Comparable を実装するか Comparator を実装するかは問題ではないことに注意してください。a の場合、SortedSetいずれかが equals と一致している必要があります。PriorityQueueCollection.sortArrays.sort

TreeSetとの一貫性equals

コメントから持ち上げた:

TreeSetSortedSet であり、compareTo/compare のみに依存することを明示的に示しています。「セットの動作は、その順序が equals と矛盾していても、明確に定義されています。単に Set インターフェースの一般的な契約に従わないだけです。」

引用する場合は、関連するすべての部分を引用してください。完全な段落は次のとおりです。

インターフェースを正しく実装するためには、(明示的なコンパレーターが提供されているかどうかに関係なく) セットによって維持される順序付けがequals と一致している必要があることに注意してください。Set[...] これは、インターフェイスが操作Setの観点から定義されているためですが、インスタンスはその(または) メソッドを使用してすべての要素の比較を実行するため、このメソッドによって等しいと見なされる 2 つの要素は、セット、等しい。セットの動作は、その順序付けが equals と一致しない場合でも明確に定義されています。インターフェイスの一般的な契約に従わないだけです。equalsTreeSetcompareTocompareSet

はい、それは明確に定義されていますが、質問が要求することはしません:セット内の別のタイムスタンプと同じタイムスタンプを持つTreeSet.addを渡すと、新しいものは重複していると見なされ、追加されません。ありません。質問は、;の並べ替えについて尋ねます。ソートキーの重複を排除するべきではありませんか?EventEventEventEventequalCollectionEvents

于 2011-06-25T17:12:37.953 に答える
4

cによってSに課される順序が等しいと矛盾する場合、ソートされたセット(またはソートされたマップ)は奇妙に動作します。

つまり、その場合に限りe1.equals(e2)ますe1.compareTo(e2) == 0

そして、その場合に限り!e1.equals(e2)ますe1.compareTo(e2) != 0

それはあなたが両方の方法を一貫させるためにしなければならないことです。

したがって、compareToを実装する方法では、equals()を次のようにオーバーライドする必要もあります。

@Override
public boolean equals(Event e) {
    return this.timestamp.equals(e.timestamp);
}

注:タイムスタンプのデータ型はわかりませんが、プリミティブ型の場合は、オーバーライドされたメソッドの==代わりにを使用してください。equals()

于 2011-06-25T14:06:51.290 に答える
0

実装するときは、 true を返す場合にのみゼロを返す必要があるため、Comparableもオーバーライドする必要があります。equals(Object)compareToequals

equals(Object) が true を返す場合にのみ、compareTo(T) はゼロを返す必要があります。

それだけではありません。別のコントラクトにより、オーバーライドhashCode()するときにオーバーライドする必要がありますequals

等しいオブジェクトには、等しいハッシュコードが必要です。

public class Event implements Comparable<Event> {

    private long timestamp;

    public long getTimestamp() {
        return this.timestamp;
    }

    @Override
    public int compareTo(Event o) {
        return (this.timestamp < o.timestamp ? -1
                : (this.timestamp == o.timestamp ? 0 : 1));
    }

    @Override
    public int hashCode() {
        return (int) (this.timestamp ^ (this.timestamp >>> 32));
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Event) {
            return this.timestamp == ((Event) obj).timestamp;
        }

        return false;
    }

}

compareToequalsあり、hashCode実装は で確認できる実装から取得されましたjava.lang.Long。これらのメソッドは、Eclipse などの IDE で生成することもできます。

equals が false を返さなければならないときに 0 に評価される compareTo が必要な場合 (別のコメントで述べたように)、Comparable を実装する代わりに Comparator を実装する必要があります。

public class EventComparator implements Comparator<Event>, Serializable {

    private static final long serialVersionUID = 1L;

    @Override
    public int compare(Event o1, Event o2) {
        return (o1.getTimestamp() < o2.getTimestamp() ? -1
                : (o1.getTimestamp() == o2.getTimestamp() ? 0 : 1));
    }

}
于 2011-06-25T14:14:40.070 に答える