Java 使用HashMaps中的对象作为键

Java 使用HashMaps中的对象作为键,java,hashmap,Java,Hashmap,因此,我有一个小问题,我不能缠绕我的头 我需要将一个类对象作为键存储在映射中,以便稍后由一个新创建的对象对照映射检索它。我有一个类,它实现了Cloneable并覆盖toString,hashCode和equals,但似乎该对象是唯一的,无论我如何创建该对象以用作从映射检索值的键,应该匹配该键的新对象都不会 对象类: package com.keneti.tekkit.objects; 导入org.bukkit.block.block; 导入org.bukkit.inventory.ItemSta

因此,我有一个小问题,我不能缠绕我的头

我需要将一个类对象作为键存储在映射中,以便稍后由一个新创建的对象对照映射检索它。我有一个类,它实现了
Cloneable
并覆盖
toString
hashCode
equals
,但似乎该对象是唯一的,无论我如何创建该对象以用作从映射检索值的键,应该匹配该键的新对象都不会

对象类:
package com.keneti.tekkit.objects;
导入org.bukkit.block.block;
导入org.bukkit.inventory.ItemStack;
导入com.keneti.main.KenetiPrereq;
/**用ID:DATA表示块的简单对象。
* 
*@作者迈克尔·梅森*/
公共类SimpleBlock实现可克隆{
受保护的最终int id;
受保护字节数据;
/**创建数据值为零的新SimpleBlock对象。
* 
*@param id块id*/
公共SimpleBlock(int-id){
this.id=id;
这个数据=0;
}
/**创建新的SimpleBlock对象。
* 
*@param id块id。
*@param data要设置的块数据*/
公共SimpleBlock(int-id,字节数据){
this.id=id;
这个数据=数据;
}
/**从{@link Block}创建新的SimpleBlock对象。
* 
*@param block是一个bukkit block*/
公共SimpleBlock(块){
这是(block.getTypeId(),block.getData());
}
/**从{@link ItemStack}创建新的SimpleBlock对象。
* 
*@param itemStack是一个bukkit itemStack*/
公共SimpleBlock(ItemStack ItemStack){
这是(itemStack.getTypeId(),itemStack.getData().getData());
}
/**获取此块的ID。
* 
*@返回此块的ID*/
公共int getId(){
返回id;
}
/**获取此块的数据。
* 
*@返回此块的数据*/
公共字节getData(){
返回数据;
}
/**设置此块的数据。
* 
*@param data要为此块设置的数据*/
公共无效设置数据(字节数据){
这个数据=数据;
}
@凌驾
公共对象克隆(){
试一试{
SimpleBlock s=(SimpleBlock)super.clone();
返回s;
}
捕获(CloneNotSupportedException e){
KenetiPrereq.journal.fine(“CloneNotSupportedException:SimpleBlock”+this.toString());
抛出新错误(e);
}
}
@凌驾
公共字符串toString(){
返回“{SimpleBlock:“+this.id+”:“+this.data+”}”;
}
@凌驾
公共int hashCode(){
返回此.toString().hashCode();
}
@凌驾
公共布尔等于(对象obj){
if(SimpleBlock的obj实例)返回(this.id==((SimpleBlock)obj.id)&&(this.data==((SimpleBlock)obj.data);
if(obj instanceof ItemStack)返回(this.id==((ItemStack)obj.getTypeId())&&(this.data==((ItemStack)obj.getData());
if(obj instanceof Block)返回(this.id==((Block)obj.getTypeId())&&(this.data==((Block)obj.getData());
返回false;
}
}
运行代码
//保存值的映射
私有LinkedHashMap位置映射;
//我像这样创建SimpleBlock对象
SimpleBlock sb=新的SimpleBlock(758,(字节)14);
//我使用SimpleBlock对象作为键添加位置。
位置示意图(sb,位置);
后来,在另一节课上:
//因此在获取局部变量中的映射后。。
LinkedList locations=locationsMap.get(新的SimpleBlock(758,(字节)14));
当我尝试使用相同的创建数据获取对象时,它在映射中看不到该对象(尽管我在单步执行代码时看到它,但它肯定在那里)

我的问题是,这目前如何不起作用?我确信我已经完成了使对象相等所需的步骤


提前感谢您:D

equals和hashcode的实现不符合合同要求(请参阅)

简言之,SimpleBlock对象可以等于另一个对象,但具有不同的哈希代码

如果根据equals(Object)方法,两个对象相等,则 对两个对象中的每一个调用hashCode方法都必须产生 相同的整数结果

解决这个问题,我想你会解决你的问题


编辑:此外,使用库来构建equals和hashcode方法将使其更容易:并且

在对象存储在映射中后,您可能正在对其进行变异(即调用其设置器之一)。使您的类不可变。一个SimpleBlock可以等于另一个SimpleBlock之外的东西这一事实是非常可疑的。另外,尝试使用sb变量从HashMap中获取它,这样您就可以验证这是否是问题所在。@JB Nizet SimpleBlock还可以等于
项堆栈
,以方便使用其他方法,你会建议不要这样做吗?@Zachery我知道我在那里做了什么,最后一行在另一个类中,完全没有访问sb变量的权限。我会做一些快速编辑。谢谢。正如Chii的回答所解释的,这将打破equals()的约定,除非相等的ItemStack和相等的块也具有相同的哈希代码。如果simpleBlock.equals(其他对象)为true,但otherObject.equals(simpleBlock)为false,那么它也破坏了equals()的约定。
@Override public int hashCode(){返回this.toString().hashCode();}
返回相同的整数结果吗?我不知道您实际运行的是什么代码(您给出的示例将返回正确的结果,因此很明显,其他一些东西是错误的)。但我怀疑您在查询时实际使用的不是SimpleBlock,而是应该与SimpleBlock相等的其他东西。但是