クラスcompareTo()
と矛盾する場合、誰かが結果を明らかにすることができますか。であることが必須ではない場合、それequals()
を読んだことがあります。しかし、これが起こった場合の結果はどうなりますか。ありがとう。Obj1.compareTo(Obj2) = 0
Obj1.equals(Obj2) = true
3 に答える
のドキュメントでComparable
は、これについて詳しく説明しています。
クラスの自然な順序付けは、クラスのすべてのおよびクラスと同じブール値を持つ場合にのみ、
C
一貫性があると言われます。はどのクラスのインスタンスでもないことに注意してください。equals
e1.compareTo(e2) == 0
e1.equals(e2)
e1
e2
C
null
e.compareTo(null)
NullPointerException
e.equals(null)
false
自然な順序付けが と一致することを強くお勧めします (必須ではありません)
equals
。これは、明示的な比較子のないソートされたセット (およびソートされたマップ) が、自然な順序付けが と一致しない要素 (またはキー) で使用されると、「奇妙な」動作をするためequals
です。特に、そのようなソートされたセット (またはソートされたマップ) は、メソッドに関して定義されているセット (またはマップ) の一般的な規約に違反していequals
ます。たとえば、明示的なコンパレータを使用しないソート済みセットに 2 つのキー を追加すると、2 番目の追加操作が返されます
a
(ソート済みセットのサイズは増加しません) 。b
(!a.equals(b) && a.compareTo(b) == 0)
false
a
b
を実装する事実上すべての Java コア クラス
Comparable
は、equals
. 1 つの例外はjava.math.BigDecimal
で、その自然な順序付けでは、BigDecimal
値が等しく精度が異なるオブジェクト ( と など4.0
)が同等と見なされます4.00
。
ドキュメントには一貫性は必須ではないと書かれていますが、オブジェクトがいつかTreeMap
/などに存在するかどうかわからないため、常にこの一貫性を確保することをお勧めしますTreeSet
。compareTo()
等しくない 2 つのオブジェクトに対して 0 を返す場合、すべてのツリー ベースのコレクションが壊れています。
たとえば、Query
2 つのフィールドを持つ 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;
}
一部のコレクションは、2 つのオブジェクトが続く場合も true であると想定しobj1.compareTo(obj2) = 0
ますobj1.equals(obj2)
。例TreeSet
: このロジックを満たさないと、iconsistent コレクションが発生します。参照:
コンパレータと equals()。