具有相同hashCode的等同对象不会映射到HashMap中的相同值

时间:2016-01-20 12:09:49

标签: java

我使用自定义类Vec作为HashMap中的密钥。

但两个具有相同Vec的相同hashCode()个对象不会映射到同一个键。

我做错了什么?

import java.util.HashMap;

/**
 * A 2-element float Vector
 */
class Vec {
    public float x;
    public float y;

    public Vec(float x, float y) {
        this.x = x;
        this.y = y;
    }

    public Vec(Vec v) {
        this.x = v.x;
        this.y = v.y;
    }

    public boolean equals(Vec v) {
        System.out.println("equals called");
        return (x == v.x &&
                y == v.y);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = (Float.floatToIntBits(x)
                      + prime * Float.floatToIntBits(y));
        System.out.println("hash called: " + result);
        return result;
    }
}

public class Debug {
    public static final void main(String[] args) {
        Vec v1 = new Vec(3, 5);
        Vec v2 = new Vec(v1);
        System.out.println("vecs equal: " + v1.equals(v2));
        System.out.println("hashcodes: " + v1.hashCode() + ", " + v2.hashCode());

        System.out.println("\nuse map");
        HashMap<Vec, Object> map = new HashMap<>();
        map.put(v1, new Object());
        Object o1 = map.get(v1);
        Object o2 = map.get(v2);
        System.out.println(o1);
        System.out.println(o2);
        if (o2 == null) {
            throw new RuntimeException("expected o2 not to be null");
        }
    };
}

输出

equals called
vecs equal: true
hash called: 329252864
hash called: 329252864
hashcodes: 329252864, 329252864

use map
hash called: 329252864
hash called: 329252864
hash called: 329252864
java.lang.Object@2a139a55
null
Exception in thread "main" java.lang.RuntimeException: expected o2 not to be null

2 个答案:

答案 0 :(得分:9)

这是你的问题:

public boolean equals(Vec v) {
                      ^^^

我建议始终使用@Override注释 - 在这种情况下,它会为您提供编译错误 ,因为您没有覆盖Object::equals

将签名更改为:

public boolean equals(Object v) {
                      ^^^^^^

并修改实现,你应该得到你期望的行为。

答案 1 :(得分:-2)

您需要使用@Override注释equals并使用Object作为Parameter-Class 例如:

@Override public boolean equals(Object aThat) {
//check for self-comparison
if ( this == aThat ) return true;

//use instanceof instead of getClass here for two reasons
//1. if need be, it can match any supertype, and not just one class;
//2. it renders an explict check for "that == null" redundant, since
//it does the check for null already - "null instanceof [type]" always
//returns false. (See Effective Java by Joshua Bloch.)
if ( !(aThat instanceof Car) ) return false;
//Alternative to the above line :
//if ( aThat == null || aThat.getClass() != this.getClass() ) return false;

//cast to native object is now safe
Car that = (Car)aThat;

//now a proper field-by-field evaluation can be made
return
  EqualsUtil.areEqual(this.fName, that.fName) &&
  EqualsUtil.areEqual(this.fNumDoors, that.fNumDoors) &&
  EqualsUtil.areEqual(this.fOptions, that.fOptions) &&
  EqualsUtil.areEqual(this.fGasMileage, that.fGasMileage) &&
  EqualsUtil.areEqual(this.fColor, that.fColor) &&
  Arrays.equals(this.fMaintenanceChecks, that.fMaintenanceChecks);}