繁体   English   中英

鉴于我已经拥有密钥,HashMap 正在获取密钥

[英]HashMap getting key given that I already have the key

这听起来像是一个非常奇怪的请求,但我有一个自定义类的HashMap 我已经覆盖了equalshashCode方法以只关注某些字段,这样我就可以在它等于具有相同某些字段的新键时拉出一个键。 在这种情况下,我想用一些新值替换其他字段。 结构是这样的:

public class ExampleClass() {
   int field1;
   int field2;

   <insert constructor here with field1 and field2>

   @Override
   public boolean equals(Object obj) { // Only return true if field1 is equal
      ...
      return (this.field1 == obj.field1);
   }
}

所以我像这样使用它:

HashMap<ExampleClass, int> hmap = new HashMap<>();
while(true) {
   ...
   ExampleClass oldObject = new ExampleClass(1, 2);
   ExampleClass newObject = new ExampleClass(1, 5);

   hmap.put(oldObject, 10);
   if(hmap.contains(newObject)) {
      // Get field1 of old object and change it
   }
}

这是一个不好的例子,但我只想能够在HashMap检索键值对的键对象,因为我有键,以便我可以修改键。 我该怎么做?

编辑:我的哈希码函数。

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + 
            ((this.srcVertex.getVertexData().getID() == null) ? 0 : this.srcVertex.getVertexData().getID().hashCode());
    result = prime * result + 
            ((this.targetVertex.getVertexData().getID() == null) ? 0 : this.targetVertex.getVertexData().getID().hashCode());
    return result;
  }

据我了解您的问题,您在 HashMap 中有一个键对象,并且您想使用“相等”键对象来检索键而不是与其关联的值。 HashMap 上没有方法可以做到这一点,如果您确实关心获得的两个相等对象中的哪一个,那么它在某种程度上违反了两个对象“相等”的想法。

我认为以不同的方式执行此操作会更有意义:

  • 编写一个新类ExampleKey其中仅包含您想在equals / hashCode方法中用于 HashMap 的字段。 此类必须使用这些字段覆盖equalshashCode ,并且它应该是不可变的(如果键的哈希值在 HashMap 中可以更改,则行为未定义)。
  • ExampleClass一个getKey()方法,该方法返回当前对象的ExampleKey对象。 在这里使用组合可能更简单,因此ExampleClass不会重复这些字段。
  • 现在有两个 HashMap:一个Map<ExampleKey, Integer>用于您要存储的实际映射,以及一个单独的Map<ExampleKey, ExampleClass>存储对象,否则该对象将被用作另一个 HashMap 中的键。

用法示例:

Map<ExampleKey, Integer> actualMapping = new HashMap<>();
Map<ExampleKey, ExampleClass> objsUsed = new HashMap<>();
while(true) {
   // ...
   ExampleClass oldObject = new ExampleClass(1, 2);
   ExampleClass newObject = new ExampleClass(1, 5);

   // always update both maps together, to ensure valid state
   actualMapping.put(oldObject.getKey(), 10);
   objsUsed.put(oldObject.getKey(), oldObject);

   // ...

   ExampleClass objUsed = objsUsed.get(newObject.getKey());
   if(objUsed != null) {
        // objUsed == oldObject here
   }
}

如果您不关心“相等”的含义,那么您可以在没有ExampleKey类或getKey方法的情况下应用相同的解决方案; 只使用对象本身,即objsUsed将是Map<ExampleClass, ExampleClass> ,它总是将对象映射到自身。 但我认为如果你这样做,你的代码的读者会挠头想知道你为什么要将对象映射到它们自己。

您忘记定义 hashCode() 方法。 没有它,将对象作为键存储在 HashMap 中是行不通的。

更新:

如果 srcVertex 是 field1 而 targetVertex 是 field2,那么你的 hashCode() 方法是不正确的。 如果equals() 比较srcVertex,那么hashCode() 应该只使用srcVertex,而不是targetVertex。

规则是:如果 2 个对象相等,则它们的哈希码必须相等。

Java 中的Map应该以在其所有“基本属性”上定义了equals值作为键。 我相信大多数收藏库都是这样工作的,唯一能想到的例子是 General Magic 的 Telescript。

因此,在仅具有这些属性的类型上定义Map 在这种情况下, field1 int ( Integer )。 将其余信息放入映射条目值中。 这很可能是一个新类。

Map<Integer, ValueClass> map;

在哪里

public final class ValueClass {
    private int someValue;
    private ExampleClass exmaple;
    ...

如果你坚持要找到钥匙,我建议你不要。 有多种方法可以做到,例如:

Optional<ExampleClass> found = map.keySet().stream()
    .firstThat(k -> k.field1() == target);
found.ifPresent(key -> {
   Integer value = hmap.remove(key);
   // update key.
   hmap.put(key, value);
});

或者旧学校版本(对我来说看起来更好,但不是那么酷):

for (ExampleClass key : map.keySet()) {
    if (key.field1() == target) {
        Integer value = hmap.remove(key);
        // update key.
        hmap.put(key, value);
    }
}

使用Iterator或可能在 ihe 条目集上使用更好,因为它避免了三个查找中的第二个,但我将把它作为练习。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM