【问题标题】:searching keys of subclass in HashMap在 HashMap 中搜索子类的键
【发布时间】:2015-08-07 08:38:23
【问题描述】:

只是尝试做类似的事情:

public class GameMap {

protected HashMap<Sector, Integer[]> mapping;

protected void loadMapFromFile(String fileLocation, int numPlayers) {

    .
    //Other stuff
    .
    .

    case "ALIENSECT":

    Integer[] someValue = {5};
    mapping.put(new AlienSector(row, col), someValue);
    break;
}

public justATestMethod() {

    System.out.println(mapping.containsKey(new Sector(6, 'L')));
}

其中AlienSectorSector 的子类。

但是当我尝试在另一个班级这样做时:

   mappa.justATestMethod();

结果为“假”。

如果我像这样重写方法“justATestMethod()”:

System.out.println(mapping.containsKey(new AlienSector(6, 'L')));

结果为“真”。

我得到“true”也改变了这行“loadMapFromFile”方法:

case "ALIENSECT":

Integer[] someValue = {5};
mapping.put(new AlienSector(row, col), someValue);
break;

这边:

case "ALIENSECT":

mapping.put(new Sector(row, col), new Integer[1]);
Integer[] aCazzo = {5};
mapping.put(new AlienSector(row, col), aCazzo);
break;

首先用Sector对象键填充HashMap,然后分配AlienSector对象键。

谁能解释一下为什么会这样? AlienSectorSector 的子类,如果我只是实例化它的子类而不先用超类“扇区”的实例实例化键,为什么 Java 无法识别 HashMap 键中存在 Sector自己?

【问题讨论】:

  • 请发布 AlientSector 和 Sector 类的 equals() 和 hashCode() 方法

标签: java inheritance hashmap polymorphism subclass


【解决方案1】:

您将 AlienSector 存储在 HashMap 中,然后尝试使用使用相同参数创建的另一个 Sector 来检索它。当您尝试从 HashMap 中检索对象时,它正在寻找与您存储的对象“相等”的对象。但是默认情况下,Java 不会仅仅因为两个对象具有相同的成员而将它们识别为“相等”。默认情况下只有当它们是同一个对象时它们才相等(字符串、整数等是特殊情况)。

您需要做的是通过覆盖“equals”方法告诉Java 具有相同参数的两个对象是“相等的”。从您的测试结果来看,您似乎已经为 AlienSector 做到了这一点。但是您需要对 Sector 和 AlienSector 执行此操作,并对其进行排列,以便即使对象具有不同的类,它们也被认为是相等的,即 AlienSector 被认为等于具有相同成员的 Sector,而 Sector 被认为等于AlienSector 具有相同的成员。有关于如何做到这一点的教程。

您还需要覆盖 hashCode() 方法,以确保任何两个被视为“相等”的对象也返回相同的 hashCode。 HashMap 使用 hashCode 作为过滤器,决定具有不同 hashCode 的事物永远不可能相等。

所有这些的细节都太长了,无法像这样回答。

顺便说一句,如果您在 containsKey 调用中使用了 相同的对象,而不是创建一个新对象,您会发现它有效。

【讨论】:

  • 基本上是我在回答中提到的,但我却被否决了 LoL
【解决方案2】:

您可以使用下面的类来执行此行为。

需要注意的一点是,如果是大地图,它的性能可能不会特别好,但在大多数情况下,地图的大小会很小,因此不会对性能产生真正的影响。

注意:JDK8+ 代码

本质上,我们覆盖了 containsKey 的常规 hashmap 类方法并开始进行适当的搜索。

import java.util.HashMap;
import java.util.Optional;

public class PolymorphicHashMap<K extends Class<?>,V> extends HashMap<K,V> {

  @Override
  public boolean containsKey(Object key) {
    return findEntry((K)key).isPresent();
  }

  @Override
  public V get(Object key) {
    var entry = findEntry((K)key);
    return entry.map(Entry::getValue).orElse(null);
  }

  private Optional<Entry<K,V>> findEntry(K key) {
    return entrySet().stream()
        .filter(e -> e.getKey().isAssignableFrom(key))
        .findFirst();
  }

}

【讨论】:

    【解决方案3】:

    HashMap 使用hashCode() 函数来查找和存储键/值对。
    我相信您需要让超类/子类都返回相同的哈希码,以便能够在 HashMap 中查找子类的键。

    public class AlienSector {
        public int hashcode() {
            //
            // Generate a hashcode unique to this AlienSector object here
            //
        }
    }
    
    public class Sector {
        public int hashCode() {
            return super.hashCode(); // Return the same hashcode as the super class
        }
    }
    

    正如评论中所指出的,规则是,如果您覆盖 hashCode() 函数,则还需要覆盖 equals() 函数(反之亦然)

    【讨论】:

    • 注意,如果他覆盖hashCode,他也应该覆盖equals,并且equals需要是对称的。 (这意味着这很少是一个好主意。)
    • HashCode 只是问题的一部分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-12
    • 2011-10-30
    • 1970-01-01
    • 1970-01-01
    • 2016-10-30
    • 2019-08-11
    • 1970-01-01
    相关资源
    最近更新 更多