Java LinkedHashMap中的NullPointerException
我正在创造一个游戏。当我阅读LinkedHashMap时,它会给我一个NPE 我填写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 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中的代码是不好的形式。您应该将问题简化为一个简短但完整的程序来演示问题