java - HashMap<String[], List<int[]>> 未检测到重复值

标签 java hashmap

如果键不存在于映射中,我将尝试向我的 HashMap 中添加数据。出于某种原因,即使 key 确实存在,hashmap 仍然会添加它。我不知道为什么会这样。我的 addEntity 方法是问题所在。我正在尝试检测 key 是否已经在 HashMap 中,如果是,则什么也不做。但是,出于某种原因,它总是会添加 key ,无论 key 是否已经存在。

我的数据文件:

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;
        //...
    }

}

最佳答案

问题是数组不会覆盖 equals也不hashCode来自 Object 的方法类,因此即使您添加一个新的 String[]具有相同的值,它将是您 map 中的不同键。

一个可能的解决方案是创建一个包装类来保存 String[]为你覆盖 equalshashCode那里的方法。

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 在这个包装类中。


来自您的评论:

My addEntity method is the problem. I am trying to detect of the key is already in the hashmap, and if it is, then do nothing. However, it for some reason will always add the key, no matter if the key already exists.

这就是我上面所解释的。方法 Map#containsKey 明确指出:

returns true if and only if this map contains a mapping for a key k such that (key==null ? k==null : key.equals(k))

因为数组不会覆盖Object#equals ,你不会有两个相似的数组键,即使它们在相同的位置有相同的元素。


编辑:根据您当前的编辑,问题在 equals 中和 hashCode方法实现。我已经基本实现了 MyStringArrayHolder类并复制/粘贴 PathingData 的代码类(class)。这按预期工作(至少对于这种情况):

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@35087359int[] 的当前哈希码.我建议从 List<int[]> 更改至 List<List<Integer>> , 但是这个实现超出了问题的范围:)。

关于java - HashMap<String[], List<int[]>> 未检测到重复值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18934974/

相关文章:

java - 发布表单时设置请求属性

java - Spring 可缓存除非条件不起作用

java - 通过 OLSMultipleLinearRegression 计算估计值

java - 在 Caliper 中使用代表

java - 根据用户定义的标准对 map 进行排序?

java - Java 中声明的库的 API 在哪里?

java - 尝试制作一个简单的食谱程序

Java HashMap 可以通过hash来访问

algorithm - 计算 HashMap 与二进制搜索的 O(n)

java - Java HashMap方法是否包含Key计算每次调用中传递的对象的哈希值