-1

私はEffective Java Item 9を読んでいて、サンプルコードを自分で実行することにしました。しかし、内部で何が起こっているのか正確にはわからない新しいオブジェクトをどのように挿入するかによって、動作が少し異なります。PhoneNumber クラスは次のようになります。

public class PhoneNumber {

private final short areaCode;
private final short prefix;
private final short lineNumber;

public PhoneNumber(int areaCode, int prefix, int lineNumber) {
    this.areaCode = (short)areaCode;
    this.prefix = (short) prefix;
    this.lineNumber = (short)lineNumber;
}

@Override public boolean equals(Object o) {
    if(o == this) return true;
    if(!(o instanceof PhoneNumber)) return false;
    PhoneNumber pn = (PhoneNumber)o;
    return pn.lineNumber == lineNumber && pn.prefix == prefix && pn.areaCode == areaCode;
}
}

それから本によると、私が試したときのように、

    public static void main(String[] args) {

         HashMap<PhoneNumber, String> phoneBook = new HashMap<PhoneNumber, String>();
         phoneBook.put(new PhoneNumber(707,867,5309), "Jenny");
         System.out.println(phoneBook.get(new PhoneNumber(707,867,5309)));
    }

HashMap には各エントリに関連付けられたハッシュ コードをキャッシュする最適化があり、ハッシュ コードが一致しない場合はオブジェクトの等価性をチェックしないため、これは "null" を出力します。それは私には理にかなっています。しかし、私がこれを行うとき:

    public static void main(String[] args) {

         PhoneNumber p1 = new PhoneNumber(707,867,5309);
         phoneBook.put(p1, "Jenny");
         System.out.println(phoneBook.get(new PhoneNumber(707,867,5309)));
    }

これで「ジェニー」が返されます。2 番目のケースで失敗しなかった理由を説明できますか?

4

4 に答える 4

1

Object.hashcode()の一般的な規約に違反しているため、結果は実装に依存するため、実際の動作は、アプリケーションの実行に使用されたJava のバージョンベンダーによって異なる場合があります。

考えられる説明 ( の考えられる実装を 1 つ取り上げますHashMap):

内部実装のHashMapクラスは、オブジェクト (キー) をハッシュコードに基づいて異なるバケットに配置します。要素を照会したり、キーがマップに含まれているかどうかを確認したりする場合、最初に、照会されたキーのハッシュコードに基づいて適切なバケットが検索されます。バケット内ではオブジェクトが順次チェックされ、バケット内ではequals()メソッドのみが要素の比較に使用されます。

したがって、オーバーライドしないObject.hashcode()と、2 つの異なるオブジェクトが同じバケットを決定する場合と決定しない場合があるデフォルトのハッシュコードを生成すると、不確定になります。万が一、それらが同じバケットを「指している」場合でも、equals()メソッドがそれらが等しいと言っていれば、キーを見つけることができます。万が一、それらが 2 つの異なるバケットを「指している」場合、equals()メソッドがそれらが等しいと言っていても、キーは見つかりません。

hashcode()オーバーライドされたメソッドと一致するようにオーバーライドする必要がありますequals()。この場合にのみ、 の適切で期待される一貫した動作が保証されHashMapます。

違反してはならない契約については、Object.hashcode()の javadoc を参照してください。要点は、別のオブジェクトをequals()返す場合、メソッドはこれらの両方のオブジェクトに対して同じ値を返さなければならないということです。truehashcode()

于 2014-07-21T06:16:00.000 に答える
0

2 番目のケースで失敗しなかった理由を説明できますか?

一言で言えば、失敗する保証はありません。2 番目の例の 2 つのオブジェクトは、最終的に同じハッシュ コードを持つ可能性があります (純粋に偶然か、コンパイラの最適化またはhashCode()JVM でのデフォルトの動作が原因である可能性が高い)。これは、あなたが説明する動作につながります。

それだけの価値があるため、コンパイラ/JVM でこの動作を再現することはできません。

于 2014-07-21T06:15:48.017 に答える
0

宣言していないため、最後に切り取ったコードはコンパイルされませんphoneBook

どちらの主要な方法もまったく同じように機能するはずです。新しく作成された HashMap のデフォルト サイズは 16 であるため、16 分の 1 の確率で Jenny が出力されます。詳細には、hashCode の下位 4 ビットのみがチェックされることを意味します。それらが等しい場合、equal メソッドが使用されます。

于 2014-07-21T15:02:07.210 に答える
0

あなたの場合、偶然にも JVM は両方のオブジェクトに対して同じ hashCode を見つけることができました。あなたのコードを実行すると、JVM で両方のケースで null が返されました。したがって、問題はコードではなくJVMが原因です。

equils() メソッドをオーバーライドするときは、毎回 hashCode() をオーバーライドすることをお勧めします。私はEffective Javaを読んでいません.Kathy SierraによるSCJPを読んでいます. したがって、詳細が必要な場合は、この本を読むことができます。いいね。

于 2014-07-21T06:55:21.123 に答える