在“put”期间,Java Hashtable使用新密钥覆盖现有密钥

时间:2011-11-30 07:03:35

标签: java hashtable

我正在尝试使用Eclipse将条目添加到Java中的哈希表中。在put操作期间,只有一个键被新键和值覆盖。哈希表的计数被正确维护,但其中一个(键,值)对丢失了。

以下是我的示例代码:

ArrayList<Double> list;
Hashtable<Val,ArrayList<Double>> numbers = new Hashtable<Val,ArrayList<Double>>();

while((line = brMyHashval.readLine()) != null)
{
    if(!(line.isEmpty()))
    {               
        String[] temp;
        temp = line.split(" ");      
        eDouble = Double.parseDouble(temp[2].toString());

        Val key = new Val(Double.parseDouble(temp[0].toString()) ,Double.parseDouble(temp[1].toString()) );

        if(!(numbers.containsKey(key)))
        {
            list = new ArrayList<Double>();
            numbers.put(key, list);

        }
        else
        {
            list = numbers.get(key);
        }
        list.add(eDouble); 
     }
}

我习惯在eclipse中内置'hashcode'和'equals'方法来比较类对象。

输入文字文件:

1.0 2.0 9.0
3.0 4.0 9.0
5.0 6.0 9.0
1.0 2.0 8.0
5.0 6.0 8.0
1.0 2.0 7.0
**7.0 8.0 7.0** // After this point a new hash entry gets added for key(7,8), But key (1,2) get deleted from the hashtable, though count gets increased to 4.
3.0 4.0 7.0
5.0 6.0 10.0
1.0 2.0 10.0
1.0 3.0 10.0
1.0 4.0 10.0

为什么在特定时刻删除密钥。?

[edit] hashcode和equals:我用eclipse自动导入这些方法 //(x,y)是(a,b)

  class Val

{
    double x;
    double y;

Val(double X, double Y)
{
    x = X;
    y = Y;
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    long temp;
    temp = Double.doubleToLongBits(x);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    temp = Double.doubleToLongBits(y);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Val other = (Val) obj;
    if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
        return false;
    if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
        return false;
    return true;
}

}

4 个答案:

答案 0 :(得分:6)

问题是您正在使用调试器来检查HashMap的内容。

我假设密钥(1,2)和(7,8)都保存在用于保存密钥的HashTable的同一个槽中。当(7,8)被添加时,(1,2)被移动到(7,8)的“后面” - 你必须检查(7,8)条目的next条目。

enter image description here

将以下内容添加到代码的末尾,以查看HashMap中的真实内容:

    for (Val key : numbers.keySet()) {
        System.out.printf("%.1f %.1f: %s%n", key.x, key.y, numbers.get(key));
    }

答案 1 :(得分:2)

上面的Sumindra意味着您要将自定义类用作Map中的键,您必须按指定的方式编写equals()和hashCode()方法。做以下(例如:

public boolean equals(K other) {
    return a == other.a && b == other.b;
}

public int hashCode() {
    return new Double(a).hashCode() ^ new Double(b).hashCode();
}

这可以保证:

  • 两个K对象如果具有相同的成员则返回相同
  • 两个K对象具有相同的hashCode(如果它们具有相同的成员)

Map密钥对象的要求是什么。

答案 2 :(得分:1)

确保哈希和等于满足他们的要求。

每个实例都应该有一个唯一的哈希值,如果它们只相等,则equals应为true。误报意味着误报值映射到同一个键。 See this link.

答案 3 :(得分:1)

我无法重现您的问题,这是我正在运行的正确代码(未简化,因为其他答案使其尽可能接近原始问题)。

public class HashProblem {

    public static class Val {
        private double x;
        private double y;

        public Val(double x, double y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            long temp;
            temp = Double.doubleToLongBits(x);
            result = prime * result + (int) (temp ^ (temp >>> 32));
            temp = Double.doubleToLongBits(y);
            result = prime * result + (int) (temp ^ (temp >>> 32));
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Val other = (Val) obj;
            if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
                return false;
            if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
                return false;
            return true;
        }
    }

    public static void main(String... args) throws Exception {
        ArrayList<Double> list;
        String line;
        BufferedReader brMyHashval = new BufferedReader(new InputStreamReader(new FileInputStream("HashProblem.txt")));
        Hashtable<Val, ArrayList<Double>> numbers = new Hashtable<Val, ArrayList<Double>>();

        while ((line = brMyHashval.readLine()) != null) {
            if (!(line.isEmpty())) {
                String[] temp;
                temp = line.split(" ");
                Double eDouble = Double.parseDouble(temp[2].toString());

                Val key = new Val(Double.parseDouble(temp[0].toString()), Double.parseDouble(temp[1].toString()));

                if (!(numbers.containsKey(key))) {
                    list = new ArrayList<Double>();
                    numbers.put(key, list);
                    System.err.println("Created " + key.x + " " + key.y);
                } else {
                    list = numbers.get(key);
                }
                list.add(eDouble);
                System.err.println("Inserted into " + key.x + " " + key.y + " value " + eDouble + " size " + list.size() + " " + list);
            }
        }
    }

我从记录中获得的输出是

Created 1.0 2.0
Inserted into 1.0 2.0 value 9.0 size 1 [9.0] 
Created 3.0 4.0
Inserted into 3.0 4.0 value 9.0 size 1 [9.0]
Created 5.0 6.0
Inserted into 5.0 6.0 value 9.0 size 1 [9.0]
Inserted into 1.0 2.0 value 8.0 size 2 [9.0, 8.0]
Inserted into 5.0 6.0 value 8.0 size 2 [9.0, 8.0]
Inserted into 1.0 2.0 value 7.0 size 3 [9.0, 8.0, 7.0]
Created 7.0 8.0
Inserted into 7.0 8.0 value 7.0 size 1 [7.0]
Inserted into 3.0 4.0 value 7.0 size 2 [9.0, 7.0]
Inserted into 5.0 6.0 value 10.0 size 3 [9.0, 8.0, 10.0]
Inserted into 1.0 2.0 value 10.0 size 4 [9.0, 8.0, 7.0, 10.0]
Created 1.0 3.0
Inserted into 1.0 3.0 value 10.0 size 1 [10.0]
Created 1.0 4.0
Inserted into 1.0 4.0 value 10.0 size 1 [10.0]

这不是你所期望的吗?

其他答案有关于简化hashCode和equals的好处。此外,您不需要对已经是字符串的对象执行toString()。