27

私はハッシュマップを持っています:

Map<LotWaferBean, File> hm = new HashMap<LotWaferBean, File>();

LotWaferBean lw = new LotWaferBean();
... //populate lw
if (!hm.containsKey((LotWaferBean) lw)) {
  hm.put(lw, triggerFiles[l]);
}

のコードLotWaferBean

@Override
public boolean equals(Object o) {
        if (!(o instanceof LotWaferBean)) {
              return false;
        }
        if (((LotWaferBean) o).getLotId().equals(lotId)
                    && ((LotWaferBean) o).getWaferNo() == waferNo) {
              return true;
        }
        return false;
  }

私のIDEでは、ブレークポイントを設定しましequals()たが、実行されません。なんで?

4

6 に答える 6

43

hashCode()にブレークポイントを設定してみてください。

マップ内の2つのオブジェクトのhashCode()が同じ数を返す場合、equalsが呼び出され、それらが本当に等しいかどうかが判別されます。

于 2011-01-06T04:36:24.630 に答える
5

2つのhashCodesが等しい場合にのみ、ループキーequals()中に呼び出されます。

于 2011-01-06T05:10:40.550 に答える
5

JVMは、そのオブジェクトのハッシュコードのハッシュコードバケットをチェックします。同じハッシュコードを持つオブジェクトがさらにある場合は、equals()メソッドのみが実行されます。また、開発者は、hashCode()メソッドとequals()メソッドの間の正しいコントラクトに従う必要があります。

于 2011-01-06T04:41:51.523 に答える
3

2つのhashCodesが等しい場合にのみ、equals()がループキー中に呼び出されます。

これは正解です...またはほとんど。正確には、2つのハッシュコードが衝突した場合(同じであるため、適切なハッシュマップimplの下で衝突するようにバインドされます)、同等性チェックが実行されます。

于 2011-01-06T10:33:52.610 に答える
1

ところで、あなたの同等の方法はおそらく間違っています。LotWaferBeanオーバーライドされた場合、equalsメソッドはサブクラスインスタンスを受け入れますが、サブクラスも受け入れますか?

それは読むべきです:

@Override
public boolean equals(Object o) {
    if (o == null || o.getClass() != getClass()) { // << this is important
        return false;
    }

    final LotWaferBean other = (LotWaferBean)o;
    return other.getLotId().equals(lotId)
                && other.getWaferNo() == waferNo);
}
于 2011-01-06T11:18:40.367 に答える
0

Abimaran Kugathasanが指摘したように、HashMap実装は、ハッシュバケットを使用してキーを効率的に検索し、equals()のみを使用して、一致するハッシュバケット内のキーを指定されたキーと比較します。キーがHashMapに追加されるときに、キーがハッシュバケットに割り当てられることに注意してください。追加後にHashMapのキーを変更すると、ハッシュコードが変更されるようになり、適切なハッシュバケットに含まれなくなります。一致するキーを使用してマップにアクセスしようとすると、適切なハッシュバケットが見つかりますが、変更されたキーは含まれません。

class aMutableType {
   private int value;
   public aMutableType(int originalValue) {
     this.value = originalValue;
   }
   public int getValue() {
     return this.value;
   }
   public void setValue(int newValue) {
     this.value = newValue;
   }
   @Override
   public boolean equals(Object o) {
       // ... all the normal tests ...
       return this.value == ((aMutableType) o).value;
   }
   @Override
   public int hashCode() {
       return Integer.hashCode(this.value);
   }
}
...
Map<aMutableType, Integer> aMap = new HashMap<>();
aMap.put(new aMutableType(5), 3); // puts key in bucket for hash(5)
for (aMutableType key : new HashSet<>(aMap.keySet()))
    key.setValue(key.getValue()+1);  // key 5 => 6
if (aMap.containsKey(new aMutableType(6))
    doSomething();  // won't get here, even though
                    // there's a key == 6 in the Map,
                    // because that key is in the hash-bucket for 5

これにより、かなり奇妙な動作が発生する可能性があります。theMap.containsKey(theKey)の直前にブレークポイントを設定し、theKeyの値がtheMapのキーと一致することを確認できますが、キーのequals()は呼び出されず、containsKey()はfalseを返します。

ここhttps://stackoverflow.com/a/21601013に記載されているように、実際には、キーの可変タイプの使用に関して、JavaDocforMapに警告があります。非ハッシュマップタイプにはこの特定の問題はありませんが、キーがインプレースで変更されると他の問題が発生する可能性があります。

于 2016-12-07T04:36:09.240 に答える