6

クラスcompareTo()と矛盾する場合、誰かが結果を明らかにすることができますか。であることが必須ではない場合、それequals()を読んだことがあります。しかし、これが起こった場合の結果はどうなりますか。ありがとう。Obj1.compareTo(Obj2) = 0Obj1.equals(Obj2) = true

4

3 に答える 3

12

のドキュメントでComparableは、これについて詳しく説明しています。

クラスの自然な順序付けは、クラスのすべてのおよびクラスと同じブール値を持つ場合にのみ、C一貫性があると言われます。はどのクラスのインスタンスでもないことに注意してください。equalse1.compareTo(e2) == 0e1.equals(e2)e1e2Cnulle.compareTo(null)NullPointerExceptione.equals(null)false

自然な順序付けが と一致することを強くお勧めします (必須ではありません) equals。これは、明示的な比較子のないソートされたセット (およびソートされたマップ) が、自然な順序付けが と一致しない要素 (またはキー) で使用されると、「奇妙な」動作をするためequalsです。特に、そのようなソートされたセット (またはソートされたマップ) は、メソッドに関して定義されているセット (またはマップ) の一般的な規約に違反していequalsます。

たとえば、明示的なコンパレータを使用しないソート済みセットに 2 つのキー を追加すると、2 番目の追加操作が返されますa(ソート済みセットのサイズは増加しません) 。b(!a.equals(b) && a.compareTo(b) == 0)falseab

を実装する事実上すべての Java コア クラスComparableは、equals. 1 つの例外はjava.math.BigDecimalで、その自然な順序付けでは、BigDecimal値が等しく精度が異なるオブジェクト ( と など4.0)が同等と見なされます4.00

于 2013-03-22T14:32:14.467 に答える
3

ドキュメントには一貫性は必須ではないと書かれていますが、オブジェクトがいつかTreeMap/などに存在するかどうかわからないため、常にこの一貫性を確保することをお勧めしますTreeSetcompareTo()等しくない 2 つのオブジェクトに対して 0 を返す場合、すべてのツリー ベースのコレクションが壊れています。

たとえば、Query2 つのフィールドを持つ SQL クエリを実装するclass を想像してください。

  • tableList: テーブルのリスト
  • 参照: そのようなクエリを使用するプログラムのリスト

tableList が等しい場合、つまりtableListがこのオブジェクトの自然キーである場合、2 つのオブジェクトは等しいとします。hashCode()フィールドequals()のみを考慮しますtableList

public class Query implements Comparable {
    List<String> tableList;
    List<String> references;

    Query(List<String> tableList, List<String> references) {
        this.tableList = tableList;
        this.references = references;
        Collections.sort(tableList); // normalize
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 53 * hash + Objects.hashCode(this.tableList);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Query other = (Query) obj;
        return Objects.equals(this.tableList, other.tableList);
    }
}

並べ替えを参照の数に沿って行いたいとしましょう。コードを素朴に書くと、次のcompareTo()ようなメソッドが生成されます。

public int compareTo(Object o) {
    Query other = (Query) o;
    int s1 = references.size();
    int s2 = other.references.size();
    if (s1 == s2) {
        return 0;
    }
    return s1 - s2;
}

等価性とソートは 2 つの別々のフィールドで行われるため、これまでのところ問題ないようです。

ただし、 が aTreeSetまたは aTreeMapに置かれると、壊滅的です。これらのクラスの実装では、compareTo が 0 を返す場合、要素が等しいと見なされます。この場合、同じ数の参照を持つ各オブジェクトは実際には「等しい」オブジェクトであることを意味しますが、明らかにそうではありません。

より良いcompareTo()方法は次のとおりです。

public int compareTo(Object o) {
    Query other = (Query) o;
    // important to match equals!!!
    if (this.equals(other)) {
        return 0;
    }
    int s1 = references.size();
    int s2 = other.references.size();
    if (s1 == s2) {
        return -1; // not 0, they are NOT equal!
    }
    return s1 - s2;
}
于 2015-01-03T14:32:53.467 に答える
1

一部のコレクションは、2 つのオブジェクトが続く場合も true であると想定しobj1.compareTo(obj2) = 0ますobj1.equals(obj2)。例TreeSet: このロジックを満たさないと、iconsistent コレクションが発生します。参照: コンパレータと equals()

于 2013-03-22T14:35:26.813 に答える