如果地图中不存在该键,我正在尝试将数据添加到我的hashmap。出于某种原因,即使密钥确实存在,哈希映射也会添加它。我不知道为什么会这样。我的addEntity方法就是问题所在。我试图检测键已经在hashmap中,如果是,则什么都不做。但是,无论密钥是否已存在,它都会出于某种原因始终添加密钥。
我的数据文件:
package timeTraveler.mechanics;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import net.minecraft.entity.EntityLiving;
public class PathingData
{
/**
* Entity data array
*/
public static Map<String[], List<int[]>> allEntityData;
public PathingData()
{
allEntityData = new HashMap<String[], List<int[]>>();
}
/**
* Adds an entity UUID (Unique ID)and MobType to the entity data ArrayList. If the entity already exists inside of the ArrayList, then it skips it.
* @param uuid
*/
public void addEntity(String[] entityData)
{
System.out.println(entityData[0]);
if(!allEntityData.containsKey(entityData))
{
System.out.println("Adding entity!");
allEntityData.put(entityData, new ArrayList<int[]>());
}
else
{
System.out.println("ENTITY ALREADY EXISTS IN ARRAY");
}
}
/**
* Adds data (X, Y, and Z) to the corresponding UUID (Unique ID) for the entity. If the entity's UUID does not exist, then it prints out a line that says the UUID cannot be found.
* @param uuid
* @param data
*/
public void addData(String[] entityData, String data)
{
System.out.println(entityData[0]);
if(allEntityData.containsKey(entityData))
{
System.out.println("Adding data to entity!");
int[] rawData = new int[3];
String[] pureData = data.split(",");
rawData[0] = Integer.parseInt(pureData[0]);
rawData[1] = Integer.parseInt(pureData[1]);
rawData[2] = Integer.parseInt(pureData[2]);
List<int[]> entityLocData = allEntityData.get(entityData);
entityLocData.add(rawData);
allEntityData.put(entityData, entityLocData);
}
else
{
System.out.println("ENTITY DOES NOT EXIST IN ARRAY! :(");
//addEntity(entityData);
}
}
/**
* Gets the data for a specific UUID (Unique ID) for an entity.
* @param uuid
* @return
*/
public List<int[]> getDataForUUID(String[] entityData)
{
List<int[]> entityLoc = allEntityData.get(entityData);
return entityLoc;
}
/**
* Clears all entities and their corresponding data from the map.
*/
public void clearAllEntitiesAndData()
{
allEntityData.clear();
}
/**
* Checks if entity exists inside of array
* @param uuid
* @return
*/
public boolean doesEntityExist(String[] entityData)
{
List<int[]> entityLoc = allEntityData.get(entityData);
if(entityData != null)
{
return true;
}
return false;
}
}
我已经确定变量只有一个实例,我总是在.addEntity和.addData中引用一个变量。有什么想法吗?
编辑:我刚刚尝试实施建议的建议。但是,它仍然打印出相同的东西,使用timetraveler.core.StringArrayHolder@0而不是数组。这是修改后的代码:package timeTraveler.mechanics;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import timeTraveler.core.StringArrayHolder;
import net.minecraft.entity.EntityLiving;
public class PathingData
{
/**
* Entity data array
*/
public static Map<StringArrayHolder, List<int[]>> allEntityData;
public PathingData()
{
allEntityData = new HashMap<StringArrayHolder, List<int[]>>();
}
/**
* Adds an entity UUID (Unique ID)and MobType to the entity data ArrayList. If the entity already exists inside of the ArrayList, then it skips it.
* @param uuid
*/
public void addEntity(StringArrayHolder entityData)
{
System.out.println(entityData);
if(!allEntityData.containsKey(entityData))
{
System.out.println("Adding entity!");
allEntityData.put(entityData, new ArrayList<int[]>());
}
else
{
System.out.println("ENTITY ALREADY EXISTS IN ARRAY");
}
}
/**
* Adds data (X, Y, and Z) to the corresponding UUID (Unique ID) for the entity. If the entity's UUID does not exist, then it prints out a line that says the UUID cannot be found.
* @param uuid
* @param data
*/
public void addData(StringArrayHolder entityData, String data)
{
System.out.println(entityData);
if(allEntityData.containsKey(entityData))
{
System.out.println("Adding data to entity!");
int[] rawData = new int[3];
String[] pureData = data.split(",");
rawData[0] = Integer.parseInt(pureData[0]);
rawData[1] = Integer.parseInt(pureData[1]);
rawData[2] = Integer.parseInt(pureData[2]);
List<int[]> entityLocData = allEntityData.get(entityData);
entityLocData.add(rawData);
allEntityData.put(entityData, entityLocData);
}
else
{
System.out.println("ENTITY DOES NOT EXIST IN ARRAY! :(");
//addEntity(entityData);
}
}
/**
* Gets the data for a specific UUID (Unique ID) for an entity.
* @param uuid
* @return
*/
public List<int[]> getDataForUUID(StringArrayHolder entityData)
{
List<int[]> entityLoc = allEntityData.get(entityData);
return entityLoc;
}
/**
* Clears all entities and their corresponding data from the map.
*/
public void clearAllEntitiesAndData()
{
allEntityData.clear();
}
/**
* Checks if entity exists inside of array
* @param uuid
* @return
*/
public boolean doesEntityExist(StringArrayHolder entityData)
{
List<int[]> entityLoc = allEntityData.get(entityData);
if(entityData != null)
{
return true;
}
return false;
}
}
和包装器:
package timeTraveler.core;
import java.util.ArrayList;
public class StringArrayHolder
{
private String[] data;
public StringArrayHolder()
{
data = new String[2];
}
public void setData(String[] data)
{
this.data = data;
}
public String[] getData()
{
return this.data;
}
@Override
public int hashCode()
{
return 0;
//...
}
@Override
public boolean equals(Object o)
{
if(data.equals(o))
{
return true;
}
return false;
//...
}
}
答案 0 :(得分:13)
问题是数组不会覆盖equals
类中的hashCode
或Object
方法,因此即使添加具有相同值的新String[]
,它也是如此将是地图中的另一个键。
一个可能的解决方案是创建一个包装类,它将为您保留String[]
并覆盖那里的equals
和hashCode
方法。
public class MyStringArrayHolder {
private String[] data;
//class constructor...
//getters and setters for the array...
@Override
public int hashCode() {
//...
}
@Override
public boolean equals(Object o) {
//...
}
}
对于equals
和hashCode
方法的实现,您可以在此包装类中使用Arrays#equals
和Arrays#hashCode
。
来自你的评论:
我的addEntity方法就是问题所在。我试图检测键已经在hashmap中,如果是,则什么都不做。但是,无论密钥是否已存在,它都会出于某种原因始终添加密钥。
这就是我上面所解释的。方法Map#containsKey
清楚地说明了这一点:
当且仅当此地图包含关键字true
的映射,k
时,才会返回
(key==null ? k==null : key.equals(k))
由于数组不覆盖Object#equals
,所以即使它们在相同位置具有相同的元素,也不会有两个相似的数组键。
编辑:根据您当前的编辑,问题出现在equals
和hashCode
方法实施中。我已经对MyStringArrayHolder
类进行了基本实现,并复制/粘贴了PathingData
类的代码。这符合预期(至少在这种情况下):
class MyStringArrayHolder {
private final String[] data;
//I do not want any client could change the array reference
//this also explains why this field doesn't have a setter
public MyStringArrayHolder(String[] data) {
this.data = data;
}
public String[] getData() {
return this.data;
}
@Override
public int hashCode() {
return Arrays.hashCode(data);
}
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (o == this) return true;
if (o instanceof MyStringArrayHolder) {
MyStringArrayHolder other = (MyStringArrayHolder)o;
return Arrays.equals(this.data, other.data);
}
return false;
}
//just to print in console for testing purposes
@Override
public String toString() {
return Arrays.deepToString(data);
}
}
public class PathingData {
//removed the static modifier, not really sure why you need it like that
public Map<MyStringArrayHolder, List<int[]>> allEntityData;
//current class implementation...
//just to print in console for testing purposes
@Override
public String toString() {
return allEntityData.toString();
}
public static void main(String[] args) {
PathingData pathingData = new PathingData();
String[] example1 = { "hello", "world" };
String[] example2 = { "luiggi", "mendoza" };
String[] example3 = { "hello", "world" };
MyStringArrayHolder holder1 = new MyStringArrayHolder(example1);
MyStringArrayHolder holder2 = new MyStringArrayHolder(example2);
MyStringArrayHolder holder3 = new MyStringArrayHolder(example3);
pathingData.addEntity(holder1);
pathingData.addEntity(holder2);
pathingData.addEntity(holder3);
pathingData.addData(holder1, "1,2,3");
pathingData.addData(holder2, "4,5,6");
pathingData.addData(holder3, "7,8,9");
System.out.println(pathingData);
}
}
输出:
Adding entity!
Adding entity!
ENTITY ALREADY EXISTS IN ARRAY
Adding data to entity!
Adding data to entity!
Adding data to entity!
{[luiggi, mendoza]=[[I@35087359], [hello, world]=[[I@5a7691c0, [I@1e5b02a6]}
注意:包含[I@35087359
的最后一行是int[]
的当前哈希码。我建议从List<int[]>
更改为List<List<Integer>>
,但此实现超出了问题的范围:)。