2

比較可能な(等しいと一致する)フィールドと比較できないフィールド(オーバーライドするかどうかがわからないクラスの)を持つクラスを考えてみますObject#equals

クラスのインスタンスが比較され、結果の順序は等しいと一致する必要があります。つまり、両方のフィールドが(のように)等しく、比較可能なフィールドの順序と一致する場合に0返されます。Object#equals私はSystem.identityHashCodeこれらの要件でカバーされていないほとんどのケースをカバーしていました(同じ比較可能であるが、他の値が異なるインスタンスの順序は任意です)が、これが最善のアプローチであるかどうかはわかりません。

public class MyClass implements Comparable<MyClass> {
    private Integer intField;
    private Object nonCompField;

    public int compareTo(MyClass other) {
        int intFieldComp = this.intField.compareTo(other.intField);
        if (intFieldComp != 0)
            return intFieldComp;
        if (this.nonCompField.equals(other.nonCompField))
            return 0;
        // ...and now? My current approach:
        if (Systems.identityHashCode(this.nonCompField) < Systems.identityHashCode(other.nonCompField))
            return -1;
        else
            return 1;
     }
}

私がここで見る2つの問題:

  • 2つのオブジェクトでが同じである場合Systems.identityHashCode、それぞれが他方よりも大きくなります。(これはまったく起こり得ますか?)
  • 私が何をしているのかを理解している限り、同じintField値と異なる値を持つインスタンスの順序は、プログラムの実行間で一貫している必要はありません。nonCompFieldSystems.identityHashCode

あれは正しいですか?もっと問題がありますか?最も重要なことは、これを回避する方法はありますか?

4

3 に答える 3

2

最初の問題は、ほとんどありませんが、発生する可能性があります (膨大な量のメモリが必要であり、非常に運が悪いと思います)。しかし、Guava のOrdering.arbitrary()によって解決されます。これは、バックグラウンドで ID ハッシュ コードを使用しますが、2 つの異なるオブジェクトが同じ ID ハッシュ コードを持つ場合の比較結果のキャッシュを維持します。

2 番目の質問については、いいえ、ID ハッシュ コードは実行間で保持されません。

于 2012-09-20T14:54:37.693 に答える
1

nonCompFieldのクラスがかなり適切な toString() を実装している場合、使用できる可能性があります

return String.valueOf(this.nonCompField).compareTo(String.valueOf(other.nonCompField));

残念ながら、デフォルトの Object.toString() はハッシュコードを使用しており、他の人が指摘したように潜在的な問題があります。

于 2012-09-20T15:25:27.883 に答える
1

Systems.identityHashCode[…] 2 つのオブジェクトで同じ […] (これは本当に起こり得るのでしょうか?)

はい、できます。Java API ドキュメントからの引用:

合理的に実用的である限りhashCode、クラスによって定義されたメソッドObjectは、個別のオブジェクトに対して個別の整数を返します。指定されたオブジェクトのクラスがオーバーライドするかどうかに関係なく、
identityHashCode(Object x)デフォルト メソッドによって返されるものと同じハッシュ コードを指定されたオブジェクトに返します。hashCode()hashCode()

そのため、ハッシュの衝突が発生する可能性があり、メモリが増え続けているにもかかわらず、ハッシュ コードが 32 ビットに固定されたままになっていると、衝突の可能性がますます高くなります。

私が理解している限り、同じintField値と異なる値を持つインスタンスの順序は、プログラムの実行間で一貫している必要はありません。nonCompFieldSystems.identityHashCode

右。同じプログラムの 1 回の呼び出しでも異なる場合が(1,foo) < (1,bar) < (1,baz)ありますfoo.equals(baz)

最も重要なことは、これを回避する方法はありますか?

比較不可能な型の各個別値を、遭遇した個別値ごとに増加するシーケンス番号にマップするマップを維持できます。

ただし、メモリ管理には注意が必要です。コードによってキー オブジェクトが到達不能になる可能性があるため、 a を使用することはできませんWeakHashMapが、同じ値の別のオブジェクトへの参照は保持されます。したがって、特定の値のすべてのオブジェクトへの弱い参照のリストを維持するか、単純に強い参照を使用して、これまでに遭遇した比較できない値はガベージ コレクションされないという事実を受け入れます。

このスキームでは、同じ順序で再現可能な値を作成しない限り、再現可能なシーケンス番号は得られないことに注意してください。

于 2012-09-20T14:54:48.337 に答える