我正在创造一个游戏。当我阅读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;
}
完整代码:
答案 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
的所需值,请使用hashcode
和toString
方法。但是对于给定的2个对象,它指的是2个不同类的实例不能相同。问题的根本原因是hm.put(new Coordinates(xa-32, ya), "gray");
和hm.get(new Coordinates(x - 32, y))
,因为两个对象都不同。
但是,为了解决此问题,您可以覆盖hashCode
类中的toString
和Coordinates
方法,以便每次为给定的坐标提供相同的哈希码。希望这会有所帮助并为您提供正确的方向。
例如。
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方法。