Java LinkedHashMap中的NullPointerException

Java LinkedHashMap中的NullPointerException,java,nullpointerexception,linkedhashmap,Java,Nullpointerexception,Linkedhashmap,我正在创造一个游戏。当我阅读LinkedHashMap时,它会给我一个NPE 我填写LinkedHashMap hm如下: for (String s : line.split("")) { if (s.contains("*")) { hm.put(new Coordinates(xa-32, ya), "gray"); } else if (s.contains("#")) { hm.put(new Coordinates(xa-32, ya)

我正在创造一个游戏。当我阅读LinkedHashMap时,它会给我一个NPE

我填写
LinkedHashMap hm
如下:

for (String s : line.split("")) {
    if (s.contains("*")) {
        hm.put(new Coordinates(xa-32, ya), "gray");
    } else if (s.contains("#")) {
        hm.put(new Coordinates(xa-32, ya), "black");
    }
    // other code...
}
稍后,我尝试像这样从HashMap获取颜色,并获得NPE:

if ((keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_A)
    && isPainted && hm.get(new Coordinates(x - 32, y)).equalsIgnoreCase("gray")) {
    x -= 32;
}
完整代码如下:

在这一行
hm.get(新坐标(x,y-32)).equalsIgnoreCase(“灰色”)
,不可能
hm
包含新创建的坐标

创建新对象时,例如
坐标c=新坐标(x,y-32),在内存中创建该对象,变量
c
引用该内存,而不是对象本身

因此,请查看以下代码:

Coordinates c1 = new Coordinates(x, y - 32); //c1 holds reference to memory, something like "a8wgge8h"
Coordinates c2 = new Coordinates(x, y - 32); //c2 holds also reference to memory, someting like "a8w12238h"
if (c1 != c2){
   System.out.println("Yes, it is true, c1 is not c2, there are two objects with same properties, but they are not same, like human twins - they look same, but two people actually exists");
}
因此,在
hm.get(新坐标(x,y-32))
中找不到任何内容,因为它不查找具有相同
x,y
的坐标,而是查找具有相同内存引用的坐标。它不可能存在,因为您只需创建新对象,java将其与新内存地址关联,类似于
abnbn147
,然后您的列表/集合将查找地址为
abnbn147
的对象,该对象无法存储在那里,因为您刚刚创建了它


这个
hm.get(新坐标(x,y-32))
总是返回null。如果在null上调用方法,它将以NullPointerException结束,这发生在我所说的null对象上调用方法
equalsIgnoreCase
时。

为了使其工作,在类坐标中实现equals和hashCode方法

例如:

@Override
public int hashCode()
{
  return 10000*x+y;
}

@Override
public boolean equals(Object obj)
{
  if(obj == null)
    return false;
  if (getClass() != obj.getClass())
    return false;
  Coordinates other = (Coordinates)obj;
  return x == other.getX() && y == other.getY();
}
详细解释:

LinkedHashMap使用equals方法将您的密钥与映射中已有的密钥进行比较。默认等于方法比较对象引用,所以如果

Coordinates a = new Coordinates(1, 1); 
Coordinates b = new Coordinates(1, 1);
a、 equals(b)返回false。若不重写equals方法,hashmap将找不到具有密钥的项

如果重写equals()方法,则必须实现hashCode()。 每当a.equals(b)时,a.hashCode()必须与b.hashCode()相同


hm.get(新坐标(x-32,y)).equalsIgnoreCase(“灰色”)
您不能保证hashmap包含与键
新坐标(x-32,y)
对应的任何内容,因此这很可能返回null(特别取决于坐标如何实现equals()。这将导致比较
null.equalsIgnoreCase(“灰色”)
。因此出现了空指针异常。您需要从if语句中删除hm.get()语句,并包含空检查。

这是因为您正在比较对象。要获取给定键的所需值,请使用
hashcode
toString
方法。但是,对于给定的两个对象,引用类的两个不同实例的对象不能相同。问题的根本原因是在
hm.put(新坐标(xa-32,ya),“灰色”)
hm.get(新坐标(x-32,y))
因为两个对象不同

然而,为了解决这个问题,您可以覆盖
坐标
类中的
hashCode
toString
方法,每次为给定的cordinate提供相同的hashCode。希望这将有助于并为您提供一个正确的方向

比如说

public class Cordinates {

int x, y;

public Cordinates(int x, int y) {
    super();
    this.x = x;
    this.y = y;
}

public Cordinates() {
    super();
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + x;
    result = prime * result + y;
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Cordinates other = (Cordinates) obj;
    if (x != other.x)
        return false;
    if (y != other.y)
        return false;
    return true;
}

@Override
public String toString() {
    return "Cordinates [x=" + x + ", y=" + y + "]";
}

}

每当我遇到奇怪的
NullPointerException
时,它就是%90,因为对象的列表类型未初始化。 试着写

LinkedHashMap<Coordinates, String> hm = new LinkedHashMap<>();
LinkedHashMap hm=new LinkedHashMap();
在将一些值添加到
LinkedHashMap
hm.get(新坐标(x,y-32))之前,
在您的情况下返回null。因此

hm.get(新坐标(x,y-32)).equals
表示在null抛出NPE上调用方法

为什么
hm.get(新坐标(x,y-32))
在您的情况下返回null

当您向hashmap添加键时,它会为该键创建一个hashcode并将其存储在其缓存中,在检索该键时,它会引用缓存中可用的相应hashcode

因此,在添加新坐标时,cordinate对象哈希代码将添加到hashmap中

在您的情况下,cordinate类并没有正确地重写hashcode和Equalas方法

因此,创建新坐标对象时,每个对象的哈希代码都会不同,即使它们是相同的

所以,即使创建了两个相同的对象,两个相同的cordinate对象的hashcode也会不同,因为没有覆盖hashcode,因此采用对象类hashcode

如何避免这种情况

考虑hashcode的所有属性,在坐标类中重写hashcode方法

并使用素数进行计算

public int hashCode()
{
  return 31*x+y;
}
和覆盖等于方法,如下所示

public boolean equals(Object obj)
{
  if(obj == null)
    return false;
  if (!(obj instanceof this))
    return false;

  Coordinates cordinate= (Coordinates)obj;
  return x == cordinate.getX() && y == cordinate.getY();
}
所以现在,当您创建两个相同的对象时,它们的哈希代码保持不变,并且在输入这些对象作为映射键时,它将它们标识为相同

如果您通过将键作为新对象传递(与已插入键的属性相同)从映射中检索值,则它将获得非空值

最后一点

hm.put(new Coordinates(x, y - 32),"value");
这里创建了新的坐标对象,hashmap缓存了它的hashcode,稍后将在检索时用于比较

hm.get(new Coordinates(x, y - 32)); 
这还将创建一个新的坐标对象,如果我们重写了hashcode,那么它的hashcode将是相同的,因此它将获得值并为我们重新运行“value”

如果未重写,则其新hashcode值将不同,并且在检索其缓存中的hashmap搜索时,该值不可用,因此返回null


因此,请确保在cordinate类上正确重写hashcode和equals方法。

请复制完整的错误消息。是的,发布StackTrace并添加重要代码(在您获得NPE的位置),我们不需要所有的类请澄清您的问题。仅链接到pastebin中的代码是不好的形式。您应该将问题简化为一个简短但完整的程序来演示问题