简体   繁体   English

在HashMap中搜索子类的键

[英]searching keys of subclass in HashMap

just tried to do something like: 只是试图做类似的事情:

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

Where AlienSector is a subclass of Sector . 其中AlienSectorSector的子类。

But when I try to do this in another class: 但是当我尝试在另一堂课中这样做时:

   mappa.justATestMethod();

The result is "false". 结果为“假”。

Instead if I rewrite the method "justATestMethod()" like this: 相反,如果我这样重写方法“ justATestMethod()”:

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

Result is "true". 结果为“ true”。

I obtain "true" also changing this lines of "loadMapFromFile" method: 我也更改了“ loadMapFromFile”方法的这一行,获得“ true”:

case "ALIENSECT":

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

This way: 这条路:

case "ALIENSECT":

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

That is first filling the HashMap with Sector objects keys and then assigning keys of AlienSector objects. 那就是先用Sector对象键填充HashMap,然后分配AlienSector对象键。

Someone could explain me why this happens? 有人可以解释我为什么会这样吗? AlienSector is a subclass of Sector , why Java doesn't recognize the presence of a Sector in the HashMap keys if I simply instantiate a subclass of it without first instantiate the key with an istance of the superclass "Sector" itself? AlienSector是的子类Sector ,为什么Java不识别存在Sector在HashMap的键,如果我只要实现它的一个子类,而第一实例化超“部门”本身的istance的关键?

You are storing an AlienSector in the HashMap, and then trying to retrieve it with another Sector created using the same parameters. 您正在将AlienSector存储在HashMap中,然后尝试使用使用相同参数创建的另一个Sector来检索它。 When you try to retrieve an object from a HashMap it is looking for an object that is 'equal' to the one you stored . 当您尝试从HashMap检索对象时, 它正在寻找的对象与您存储的对象“相等” But by default Java does not recognize two objects as 'equal' just because they have the same members. 但是默认情况下,Java不会仅仅因为两个对象具有相同的成员就将它们识别为“相等”。 By default they are only equal if they are the same object (Strings, Integers etc. are special cases). 默认情况下,仅当它们是相同的对象时它们才相等 (字符串,整数等是特殊情况)。

What you need to do is tell Java that two objects with the same parameters are 'equal' by overriding the 'equals' method . 您需要做的是通过覆盖'equals'方法来告诉Java具有相同参数的两个对象是'equal'。 From your test results it looks like yo uhave done this for AlienSector. 从测试结果看来,您已经为AlienSector完成了此操作。 But you will need to do this for both Sector and AlienSector, and arrange it so the objects are considered equal even if they have different classes ie an AlienSector is considered equal to a Sector with the same members, and a Sector is considered equal to an AlienSector with the same members. 但是您将需要对Sector和AlienSector都执行此操作,并对其进行安排,以便即使对象具有不同的类,也认为它们是相等的,即AlienSector被视为等于具有相同成员的Sector,而Sector被视为等于一个Sector。具有相同成员的AlienSector。 There are tutorials on how to do this. 有关于如何执行此操作的教程。

You will also need to override the hashCode() method to make sure that any two objects that would be considered 'equal' also return the same hashCode. 您还需要重写hashCode()方法 ,以确保将被视为“相等”的任何两个对象也返回相同的hashCode。 HashMap uses hashCode a filter, deciding that things with different hashCodes can never be equal. HashMap使用hashCode过滤器,确定具有不同hashCodes的事物永远不会相等。

The details of all this are too long to put in an answer like this. 所有这些细节太长了,无法给出这样的答案。

by the way, if you used the same object in the containsKey call, instead of creating a new one, you would find it worked. 顺便说一句,如果您在containsKey调用中使用了相同的对象 ,而不是创建一个新的对象,您会发现它起作用。

You can use the class below to perform this behaviour. 您可以使用下面的类执行此行为。

One caveat to note is that if it is a large map, it may not be particularly performant, but for most cases the size of the map will be small so there is no real performance impact with this. 需要注意的一点是,如果地图很大,则性能可能不会特别好,但是在大多数情况下,地图的大小会很小,因此不会对性能产生实际影响。

NOTE: JDK8+ code 注意:JDK8 +代码

Essentially we override the regular hashmap class methods for containsKey and get to do the appropriate searching. 本质上,我们为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();
  }

}

HashMap uses the hashCode() function in order to lookup and store key/value pairs. HashMap使用hashCode()函数以查找和存储键/值对。
I believe you need to have both the superclass/subclass return the same hashcode in order to be able to lookup the keys of subclass in the HashMap. 我相信您需要使超类/子类都返回相同的哈希码,以便能够在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
    }
}

As pointed out in the comment, the rule is that if you override the hashCode() function, you need to override the equals() function as well (and vice-versa) 正如评论中指出的那样,规则是,如果您覆盖hashCode()函数,则还需要覆盖equals()函数(反之亦然)

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

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