在 HashMap 中搜索子类的键

searching keys of subclass in HashMap

刚刚尝试做类似的事情:

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 的子 class。

但是当我尝试在另一个 class 中执行此操作时:

   mappa.justATestMethod();

结果是"false".

相反,如果我像这样重写方法 "justATestMethod()":

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

结果是 "true"。

我得到 "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 的子 class,如果我简单地实例化一个子 [,为什么 Java 无法识别 HashMap 键中 Sector 的存在=49=] 没有首先用 superclass "Sector" 本身的实例实例化密钥?

HashMap 使用 hashCode() 函数来查找和存储 key/value 对。
我相信您需要同时拥有 superclass/subclass return 相同的哈希码才能在 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() 函数(反之亦然)

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

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

您还需要覆盖 hashCode() 方法 以确保将被视为 'equal' 的任何两个对象也 return 相同哈希码。 HashMap使用hashCode作为过滤器,决定hashCode不同的东西永远不可能相等

这一切的细节太长了,无法像这样回答。

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

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

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

注意:JDK8+ 代码

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

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();
  }

}