2014-12-05 45 views
0

据我已阅读,HashMap的不正确的equals和hashCode实现

使用对象为重点,以一个HashMap,它必须提供正确的 覆盖和执行等于hashCode 方法。 HashMap中获得(密钥K)方法调用键 对象的hashCode方法和适用返回散列值自身的静态哈希 功能找到一个桶的位置(备份阵列),其中键和 值存储在形式称为Entry(Map.Entry)的嵌套类。 HashMap的内部散列方法防止质量差的散列 函数。

为了测试这些合同,我写了一个bean类的不正确,但法律的实施等于的hashCode方法。

类:

public class HashVO { 

    private String studentName; 
    private int age; 
    private boolean isAdult; 

    public HashVO(String studentName, int age, boolean isAdult) { 
     super(); 
     this.studentName = studentName; 
     this.age = age; 
     this.isAdult = isAdult; 
    } 
    public String getStudentName() { 
     return studentName; 
    } 
    public void setStudentName(String studentName) { 
     this.studentName = studentName; 
    } 
    public int getAge() { 
     return age; 
    } 
    public void setAge(int age) { 
     this.age = age; 
    } 
    public boolean isAdult() { 
     return isAdult; 
    } 
    public void setAdult(boolean isAdult) { 
     this.isAdult = isAdult; 
    } 
    @Override 
    public String toString() { 
     return studentName + " : " + age + " : " + isAdult; 
    } 
    @Override 
    public boolean equals(Object obj) { 
     return false; 
    } 
    @Override 
    public int hashCode() { 
     return 31; 
    } 

} 

在这种情况下,HashMap中的散列法,

static final int hash(Object key) { 
     int h; 
     return (key == null) ? 0 : (h = key.hashCode())^(h >>> 16); 
    } 

也应该返回相同的值,因为每次的散列码总是返回31.因此,如果对象类HashVO被用作hashMap的键,get方法不应该工作,因为它应该去同一个桶来检索对象,并且equals方法总是返回false,所以它将不能够找到匹配fo r关键对象

但是,当我使用这个方法,

public static void main(String[] args) { 
     HashMap<HashVO, String> voMap = new HashMap<HashVO, String>(); 
     HashVO vo = new HashVO("Item1", 25, true); 
     HashVO vo1 = new HashVO("Item2", 12, false); 
     HashVO vo2 = new HashVO("Item3", 1, false); 
     voMap.put(vo, "Item"); 
     voMap.put(vo1, "Item1"); 
     voMap.put(vo2, "Item2"); 
     System.out.println(voMap.get(vo)); 
     System.out.println(voMap.get(vo1)); 
     System.out.println(voMap.get(vo2)); 
    } 

的输出是正确的,并显示

Item 
Item1 
Item2 

我想知道为什么这个正确的输出甚至未来的equals和hashCode方法实施是不正确的。

回答

2

HashMap有一个小技巧,它在使用equals之前比较了对象引用。由于您使用相同的对象引用来添加元素并检索它们,因此HashMap将正确返回它们。

请参阅Java 7的源here(Java的8做了HashMap一个相当大的改造,但它类似的东西)

final Entry<K,V> getEntry(Object key) { 
    if (size == 0) { 
     return null; 
    } 

    int hash = (key == null) ? 0 : hash(key); 
    for (Entry<K,V> e = table[indexFor(hash, table.length)]; 
     e != null; 
     e = e.next) { 
     Object k; 
     // HERE. Uses == with the key 
     if (e.hash == hash && 
      ((k = e.key) == key || (key != null && key.equals(k)))) 
      return e; 
    } 
    return null; 
} 

请注意,这不是文档的一部分,所以不依赖于它。

+0

我认为你是对的。我使用Java 8来运行程序。 Java 8中的HashMap在getNode方法中也有类似的实现(行:566)。 – Dripto 2014-12-05 15:50:46

0

HashMap中是这样的:

1)表格单元,其中(键,值)将节省计算作为key.hashCode指数();

2)HashMap中的键通过equals()或通过引用比较进行比较。

因此,在你的情况下,(K,V)的所有对将作为LinkedList存储在HashMap表的一个单元中。 而你可以从地图得到它们,因为按键的引用将等于

相关问题