LinkedHashMap中的NullPointerException

时间:2014-03-24 19:02:58

标签: 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), "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;
}

完整代码:

6 个答案:

答案 0 :(得分:10)

在这一行hm.get(new Coordinates(x, y - 32)).equalsIgnoreCase("gray"))上,hm无法包含新创建的坐标。

当您创建新对象时,例如Coordinates c = new Coordinates(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(new Coordinates(x, y - 32))中找到任何内容,因为它不会查找具有相同x,y的坐标,它会查找与内存相同的坐标。并且它不存在,因为你只是创建新对象,java将它与新的内存地址相关联,类似于abnbn147,然后你的列表/集合查找地址为abnbn147的对象,这些对象无法存储在那里,因为你刚刚创建它。

hm.get(new Coordinates(x, y - 32))始终返回null。如果你在null上调用方法,它会以NullPointerException结束,这是在我正在讨论的null对象上调用方法equalsIgnoreCase时发生的。

答案 1 :(得分:5)

为了使它工作,在类Coordinates中实现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方法将您的密钥与map中已有的密钥进行比较。默认的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()相同。

http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object) http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()

答案 2 :(得分:2)

这是因为您正在比较对象。要获得给定键LinkedHashMap的所需值,请使用hashcodetoString方法。但是对于给定的2个对象,它指的是2个不同类的实例不能相同。问题的根本原因是hm.put(new Coordinates(xa-32, ya), "gray");hm.get(new Coordinates(x - 32, y)),因为两个对象都不同。

但是,为了解决此问题,您可以覆盖hashCode类中的toStringCoordinates方法,以便每次为给定的坐标提供相同的哈希码。希望这会有所帮助并为您提供正确的方向。

例如。

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 + "]";
}

}

答案 3 :(得分:1)

在行hm.get(new Coordinates(x - 32, y)).equalsIgnoreCase("gray")中,您无法保证hashmap包含与键new Coordinates(x - 32, y)对应的任何内容,因此很可能返回null(特别是取决于Coordinates如何实现equals())。这将导致比较null.equalsIgnoreCase("gray")。因此空指针异常。您需要从if语句中删除hm.get()语句并包含空检查。

答案 4 :(得分:1)

每当我遇到奇怪的NullPointerException时,由于未初始化的List类型的对象,它是%90。 试着写

LinkedHashMap<Coordinates, String> hm = new LinkedHashMap<>();
在向LinkedHashMap

添加一些值之前

答案 5 :(得分:0)

hm.get(new Coordinates(x, y - 32))在您的情况下返回null。因此

hm.get(new Coordinates(x, y - 32)).equals表示在null上调用方法会抛出NPE。

为什么hm.get(new Coordinates(x, y - 32))在你的情况下返回null?

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

因此,在添加新坐标时,会将坐标对象哈希码添加到hashmap。

在您的情况下,cordinate类没有正确覆盖hashcode和equlas方法。

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

所以即使你创建了2个相同的对象,你的2个相同坐标对象的哈希码也会不同,因为没有哈希码覆盖,因此采用了Object类哈希码。

如何避免这种情况

考虑哈希码的所有属性

,覆盖坐标类中的哈希码方法

并使用素数进行计算

public int hashCode()
{
  return 31*x+y;
}

并覆盖equals方法,如下所示

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

所以现在当你创建2个相同的对象时,它们的哈希码保持不变,并且在输入这些对象作为映射的键时,它将它们标识为相同。

如果通过将key作为新对象(与已插入的键的属性相同)传递来从map中检索值,则它将获得非null的值。

终点

hm.put(new Coordinates(x, y - 32),"value");

这里创建了新的坐标对象,其哈希码由hashmap缓存,稍后将用于比较,同时进行比对。

hm.get(new Coordinates(x, y - 32)); 

这也将创建一个新的坐标对象,如果我们覆盖了哈希码,它的哈希码将是相同的,因此它获得了值并重新返回&#34; value&#34;对我们来说。

如果没有覆盖,则其新的哈希码值将不同,并且在其缓存中重新查找hashmap但不可用,因此返回null。

因此请确保在cordinate类中正确覆盖hashcode和equals方法。