在 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')));
}
其中 AlienSector
是 Sector
的子 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
个对象的键。
有人能解释一下为什么会这样吗? AlienSector
是 Sector
的子 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();
}
}
刚刚尝试做类似的事情:
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')));
}
其中 AlienSector
是 Sector
的子 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
个对象的键。
有人能解释一下为什么会这样吗? AlienSector
是 Sector
的子 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();
}
}