Java HashMap未检测到重复值

Java HashMap未检测到重复值,java,hashmap,Java,Hashmap,如果映射中不存在密钥,我将尝试向hashmap添加数据。出于某种原因,即使键确实存在,hashmap也会添加它。我不知道为什么会这样。我的加法就是这个问题。我试图检测hashmap中已经存在的密钥,如果存在,则什么也不做。但是,由于某种原因,它始终会添加密钥,无论该密钥是否已经存在 我的数据文件: package timeTraveler.mechanics; import java.util.ArrayList; import java.util.Collection; import jav

如果映射中不存在密钥,我将尝试向hashmap添加数据。出于某种原因,即使键确实存在,hashmap也会添加它。我不知道为什么会这样。我的加法就是这个问题。我试图检测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;
    }
}

问题是数组不会覆盖对象类中的equals或hashCode方法,因此即使添加具有相同值的新字符串[],它在映射中也将是不同的键

一个可能的解决方案是创建一个包装器类,该类将为您保存字符串[],并覆盖那里的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方法的实现,您可以在此包装器类中使用and

根据您的评论:

我的加法就是这个问题。我试图检测hashmap中已经存在的密钥,如果存在,则什么也不做。但是,由于某种原因,它始终会添加密钥,无论该密钥是否已经存在

这就是我上面解释的。该方法明确规定:

当且仅当此映射包含键k的映射且键==null时,返回true?k==null:key.equalsk

由于数组不重写Objectequals,因此即使在同一位置有相同的元素,也不会有两个相似的数组键

编辑:根据您当前的编辑,问题在于equals和hashCode方法实现中。我已经完成了MyStringGarrayHolder类的基本实现,并复制/粘贴了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);
}
}

注意:最后一行包含[I@35087359是int[]的当前哈希代码。我建议从一个列表更改为另一个列表,但此实现超出了问题的范围:。

问题是数组不重写对象类中的equals或hashCode方法,因此即使添加新字符串[]使用相同的值,它将是地图中的不同键

一个可能的解决方案是创建一个包装器类,该类将为您保存字符串[],并覆盖那里的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方法的实现,您可以在此包装器类中使用and

根据您的评论:

我的加法方法就是问题所在。我正在尝试检测hashmap中是否已经存在密钥,如果已经存在,则什么也不做。但是,出于某种原因,它将始终添加密钥,无论密钥是否已经存在

这就是我上面解释的。该方法清楚地说明了这一点:

当且仅当此映射包含键k的映射,使得key==null?k==null:key.equalsk时,返回true

由于数组不重写Objectequals,因此即使在同一位置有相同的元素,也不会有两个相似的数组键

编辑:根据您当前的编辑,问题出在equals和hashCode方法实现中。我对MyStringGarrayHolder类进行了基本实现,并复制/粘贴了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);
}
}

注意:最后一行包含[I@35087359是int[]的当前哈希代码。我建议从一个列表改为另一个列表,但这个实现超出了问题的范围:。

@Charsmud,这篇文章告诉了你这到底是为什么。为什么不使用HashMapLuiggi,你应该提到JDK中为这个用例提供的Arrays.equals和Arrays.hashCode方法。不需要包装器,只要使用它就可以了数组。asList@LuiggiMendoza抱歉,刚才看到了您关于Arrays.asList的问题。它确实实现了equals和hashCode,是的。事实上,这两个函数的行为都是在List接口中指定的,所以List的所有正确实现都必须实现这些方法和指定的行为。@Charsmud和这篇文章告诉您确切的原因是。为什么不使用HashMapLuiggi呢?您应该提到JDK中为这个用例提供的Arrays.equals和Arrays.hashCode方法。不需要包装器,只需要使用数组。asList@LuiggiMendoza抱歉,刚才看到了您关于Arrays.asList的问题。它确实实现了equals和hashCode,是的。事实上,这两个函数的行为都是在列表接口中指定,因此列表的所有正确实现都必须实现这些方法和指定的行为。的可能重复
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]}