Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java get()与继承的hashCode()方法一起正常工作,不';使用用户定义的hashCode()方法无法识别密钥_Java_Nullpointerexception_Hashmap_Hashcode - Fatal编程技术网

Java get()与继承的hashCode()方法一起正常工作,不';使用用户定义的hashCode()方法无法识别密钥

Java get()与继承的hashCode()方法一起正常工作,不';使用用户定义的hashCode()方法无法识别密钥,java,nullpointerexception,hashmap,hashcode,Java,Nullpointerexception,Hashmap,Hashcode,在我的一个类中有以下方法。它只是HashMap(名为teamOfPlayer,包含Player对象的键和Integer对象的值)的公共包装器,仅此而已 public int getTeamOfPlayer(Player p) { return teamOfPlayer.get(p); } 只要我的播放器对象从对象继承了默认的hashCode()方法,这就可以正常工作。但是,为了将播放器对象保存到文件中,我实现了自己的hashCode()。突然,该方法开始抛出NullPointe

在我的一个类中有以下方法。它只是HashMap(名为teamOfPlayer,包含Player对象的键和Integer对象的值)的公共包装器,仅此而已

public int getTeamOfPlayer(Player p)
{    
    return teamOfPlayer.get(p);
}
只要我的播放器对象从对象继承了默认的hashCode()方法,这就可以正常工作。但是,为了将播放器对象保存到文件中,我实现了自己的hashCode()。突然,该方法开始抛出NullPointerException

我将该方法扩展如下,以打印出一些调试信息,但这让我比以前更加困惑

public int getTeamOfPlayer(Player p)
{
    Object[] o = teamOfPlayer.keySet().toArray();
    Player p2 = (Player) o[0];

    System.out.println("getTeamOfPlayer(" + p + ")"
        + "\n\thash of argument is " + p.hashCode()
        + "\n\tkeySet() of hashmap is " + teamOfPlayer.keySet() 
        + "\n\tcontainsKey() of hashmap is " + teamOfPlayer.containsKey(p) 
        + "\n\tplayer extracted from keySet() is " + p2 
        + "\n\tplayer extracted from keySet() has hash of" + p2.hashCode() 
        + "\n\targument.equals(key) returns " + p.equals(p2) 
        + "\n\tkey.equals(argument) returns " + p2.equals(p));

    int i = teamOfPlayer.get(p);
    return i;
}
上述方法的输出如下:

getTeamOfPlayer(main.data.entities.Player@89f632df)
    hash of argument is -1980353825
    keySet() of hashmap is [main.data.entities.Player@89f632df]
    containsKey() of hashmap is false
    player extracted from keySet() is main.data.entities.Player@89f632df
    player extracted from keySet() has hash of-1980353825
    argument.equals(key) returns true
    key.equals(argument) returns true
异常被抛出到“inti=teamOfPlayer.get(p);”行,这意味着映射返回null(因为它认为它不包含键)。我知道这就是抛出异常的原因。然而,我认为我已经证明了关键确实存在于地图中。发生什么事了

--

更新: 下面是equals()和hashCode()方法

@覆盖
公共布尔等于(对象obj)
{
if(this==obj)
返回true;
玩家;
if(obj!=null&&obj播放器实例)
玩家=(玩家)obj;
其他的
返回false;
如果(status!=player.status | | |!name.equals(player.name)| | race!=player.race | | weeksOut!=player.weeksOut | | injuryType!=player.injuryType
||XP!=player.XP)
返回false;
对于(int i=0;i<8;i++)
{
如果(属性[i]!=player.attributes[i])
返回false;
如果(伤害[i]!=玩家伤害[i])
返回false;
}
对于(int i=0;i<28;i++)
{
if(haskill[i]!=player.haskill[i])
返回false;
}
对于(int i=0;i<4;i++)
{
if(装备[i]!=玩家装备[i])
返回false;
}
返回true;
}
@凌驾
公共int hashCode()
{
int hash=11;
散列=31*散列+状态;
hash=31*hash+name.hashCode();
散列=31*散列+竞争;
散列=31*散列+周出;
hash=31*hash+injuryType;
hash=31*hash+XP;
对于(int i=0;i<8;i++)
{
散列=31*散列+属性[i];
散列=31*散列+伤害[i];
}
对于(int i=0;i<28;i++)
hash=hash+(haskill[i]?1:0);
对于(int i=0;i<4;i++)
散列=31*散列+设备[i];
返回散列;
}

发生的事情是,您正在自动取消绑定一个
null

映射的值类型是
Integer
,而不是
int
,get方法返回
null
,这可能是因为找不到键,或者映射条目的值实际上是
null

正在爆炸的代码行:

int i = teamOfPlayer.get(p);
实际编译为:

int i = teamOfPlayer.get(p).intValue();
将包装器
整数
(可能是
null
)转换为原语
int
,原语可能不是
null

您必须处理null,例如在null的情况下尝试为
i
提供默认值:

Integer value = teamOfPlayer.get(p);
int i = value == null ? 0 : value;

这两个答案都是正确的。更具体地说

get(p)返回null(可能是因为equals()和hashcode()不同步) 然后getTeamOfPlayer()尝试将null转换为int

如果该方法返回的是整数而不是int,则不会出现此问题,或者如果将其编码为

public int getTeamOfPlayer(Player p)
{    
    Integer t = teamOfPlayer.get(p);
    if (t == null) {
        return -1;
    } 
    return t;
}
你会没事的。 也许你需要两者兼而有之。无论如何,修复HASCODE(),但是,你可能需要考虑一个不属于任何团队的玩家的合法情况。

测试的问题在于,它只证明有一对玩家的hashcode()和equals()返回true你还没有证明,对于地图上所有可能的玩家对(a,b),如果a.equals(b),那么a.hashCode()==b.hashCode()。您可能会编写这样的测试,并找到断开的地方

这一点之所以重要,是因为它还影响向映射添加条目的过程。这就是为什么hashCode()方法强制出现问题的原因。如果您获得java.lang.Object的源代码,您将在注释中看到默认hashCode实现很可能在计算hashCode时使用对象的地址。这与默认的equals()方法一起使用,该方法定义为a==b

尽管如此,还是不容易看到您违反此合同的地方,即a.equals(b)但a.hashCode()!=b、 hashCode()

一个可能的地方,我不能肯定,因为我不知道所有变量的类型是:

if (status != player.status || !name.equals(player.name) || race != player.race || weeksOut != player.weeksOut || injuryType != player.injuryType
    || XP != player.XP)
    return false;
如果其中任何一个是布尔型的,这可能不会给出预期的结果。您可能需要在每个单独的条件周围加上括号,或者更好的是,使每个条件成为单独的条件,并在每个不等式处返回false


换句话说,问题很可能是equals()的误报。

您是否覆盖了
equals
以与
hashCode
一致?请发布hashCode()和equals()的代码method@rgettman您可以从调试输出中看到,这两个对象不仅具有相同的哈希代码,但是它们也是相等的。您的hashCode()方法存在一些问题,这些问题可能会困扰您。例如,hasSkill似乎是由28个布尔数组成的数组。按照编码,任何两个具有相同数量hasSkill元素true的玩家都将拥有相同的hashCode——即使一个玩家的技能与其他任何一个都不匹配。例如,球员A可以有“好的快球”和“好的曲线球”,球员B可以有“强力击球手”和“伟大的外场速度”,并且两者都有相同的散列码。但这不是你问题的原因。得到类似Eclipse的东西。它将为您生成一个哈希代码。研究它。@Ste
if (status != player.status || !name.equals(player.name) || race != player.race || weeksOut != player.weeksOut || injuryType != player.injuryType
    || XP != player.XP)
    return false;