2011-08-10 61 views
0

我的理解是Java的HashMap实现使用指向值列表来处理碰撞的“桶”,并且如果对象的hashCode()与AND对象的equals()对于添加的对象和它碰撞的对象都是相同的。Java HashMap碰撞示例不起作用

我试着玩弄HashMap来试图看到行为中的碰撞行为,但无论我做什么,它似乎总是覆盖。

我在做什么错在这里(注意我有意留下“计数”出hashCode和等于方法)?

public class HashMapTest { 

public static void main(String[] args) { 
    HashMapTest test = new HashMapTest(); 
    test.execute(); 
} 

public void execute() { 
    HashMap<String, Node> nodeMap = new HashMap<String, Node>(); 
    Node node1 = new Node("data1", 1); 
    Node node2 = new Node("data2", 2); 

    String key = "1"; 

    System.out.println("node1 hash: " + node1.hashCode()); 
    System.out.println("node2 hash: " + node2.hashCode()); 
    System.out.println("node1 hash == node2 hash? " + (node1.hashCode() == node2.hashCode() ? "true" : "false")); 
    System.out.println("node1.equals(node2)? " + (node1.equals(node2) ? "true" : "false")); 

    nodeMap.put(key, node1); 
    System.out.println("added node1 to hash map"); 
    System.out.println("hash map size: " + nodeMap.size()); 
    System.out.println("hash map entry set size: " + nodeMap.entrySet().size()); 
    System.out.println("hash map contains node1? " + (nodeMap.containsValue(node1) ? "true" : "false")); 
    System.out.println("hash map contains node2? " + (nodeMap.containsValue(node2) ? "true" : "false")); 

    nodeMap.put(key, node2); 
    System.out.println("added node2 to hash map"); 
    System.out.println("hash map size: " + nodeMap.size()); 
    System.out.println("hash map entry set size: " + nodeMap.entrySet().size()); 
    System.out.println("hash map contains node1? " + (nodeMap.containsValue(node1) ? "true" : "false")); 
    System.out.println("hash map contains node2? " + (nodeMap.containsValue(node2) ? "true" : "false")); 
} 

protected class Node { 

    private String data; 

    private Integer count; 

    public Node(String data, Integer count) { 
     this.data = data; 
     this.count = count; 
    } 

    @Override 
    public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     result = prime * result + ((data == null) ? 0 : data.hashCode()); 
     return result; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (this == obj) 
      return true; 
     if (obj == null) 
      return false; 
     if (getClass() != obj.getClass()) 
      return false; 
     Node other = (Node) obj; 
     if (data == null) { 
      if (other.data != null) 
       return false; 
     } 
     else 
      if (!data.equals(other.data)) 
       return false; 
     return true; 
    } 


    public String getData() { 
     return data; 
    } 


    public void setData(String data) { 
     this.data = data; 
    } 


    public Integer getCount() { 
     return count; 
    } 


    public void setCount(Integer count) { 
     this.count = count; 
    } 

} 

}

它输出:

node1 hash: 95356390 
node2 hash: 95356391 
node1 hash == node2 hash? false 
node1.equals(node2)? false 
added node1 to hash map 
hash map size: 1 
hash map entry set size: 1 
hash map contains node1? true 
hash map contains node2? false 
added node2 to hash map 
hash map size: 1 
hash map entry set size: 1 
hash map contains node1? false 
hash map contains node2? true 
+0

顺便说一句,你可以简化你的'hashCode'方法来'返回数据!= null? data.hashCode():0;'不需要添加1,然后乘以31. –

回答

3

在HashMap中的密钥被散列,而不是值。在你的情况下,你打电话put(key, node),和键是恒定的,所以第二个put将覆盖第一个。如果节点是关键,那么你会有两个条目。

2

你应该看看钥匙而不是价值。

1

如果你读了javadoc for HashMap,你会注意到,put()方法的定义如下

认沽(对象键,对象的值)

将指定值与此指定键地图。

当您用put()与相同的密钥调用两次时,它将覆盖与该密钥关联的原始值。

最重要的是,该表使用的散列值(而不是值)来查找合适的存储桶。

除此之外,您对课程的理解是正确的。

但是,我不相信您可以查看公共API中的碰撞,因为这很可能是在课堂上处理的。

+0

好吧,这是有道理的。我可以修改它以使用HashMap 并更改hashCode()和equals()方法以获得冲突,并且我看到它会在密钥的hashCode()映射到的存储区中构建列表。但是,我注意到如果传递给键(K,V)的键等于()另一个键,那么它将覆盖该值。我认为它只是使用hashCode()来识别桶,然后使用equal()作为从那里的值。显然,如果关键字equal()是另一个关键字,那么它将替换关联的值。 一旦我超过了8小时的限制来回答我的问题,我会发布代码来强调这个区别。 – Caleb

+0

它使用'hashCode()'来标识桶,并且在该键上使用'equal()'方法。在成功检索一个值之前,map不知道与键关联的值是什么,所以它不能在值上使用'equal()'方法。 “HashMap”的要点是将键与值进行1:1的映射,如果单个键映射到多个值,那么它不会是一个非常有效的映射,因为它将不可能全部检索的价值! – ty1824

0

这里更新的代码使用HashMap <节点,节点>。我还更改了equals()方法以包含count字段,但将其保留在hashCode()方法之外。这成功地创建了一个碰撞,如果你看一个调试器HashMap中,你可以看到列表它是建立在有冲突的水桶:

public class HashMapTest { 

public static void main(String[] args) { 
    HashMapTest test = new HashMapTest(); 
    test.execute(); 
} 

public void execute() { 
    HashMap<Node, Node> nodeMap = new HashMap<Node, Node>(); 
    Node node1 = new Node("data1", 1); 
    Node node2 = new Node("data2", 2); 
    Node node3 = new Node("data1", 2); 
    Node node4 = new Node("data1", 1); 

    System.out.println("node1 hash: " + node1.hashCode()); 
    System.out.println("node2 hash: " + node2.hashCode()); 
    System.out.println("node3 hash: " + node3.hashCode()); 
    System.out.println("node1 hash == node2 hash? " + (node1.hashCode() == node2.hashCode() ? "true" : "false")); 
    System.out.println("node2 hash == node3 hash? " + (node2.hashCode() == node3.hashCode() ? "true" : "false")); 
    System.out.println("node1 hash == node3 hash? " + (node1.hashCode() == node3.hashCode() ? "true" : "false")); 
    System.out.println("node1.equals(node2)? " + (node1.equals(node2) ? "true" : "false")); 
    System.out.println("node2.equals(node3)? " + (node2.equals(node3) ? "true" : "false")); 
    System.out.println("node1.equals(node3)? " + (node1.equals(node3) ? "true" : "false")); 
    System.out.println(""); 

    nodeMap.put(node1, node1); 
    System.out.println("added node1 to hash map"); 
    System.out.println("hash map size: " + nodeMap.size()); 
    System.out.println("hash map entry set size: " + nodeMap.entrySet().size()); 
    System.out.println("hash map contains node1? " + (nodeMap.containsValue(node1) ? "true" : "false")); 
    System.out.println("hash map contains node2? " + (nodeMap.containsValue(node2) ? "true" : "false")); 
    System.out.println("hash map contains node3? " + (nodeMap.containsValue(node3) ? "true" : "false")); 
    System.out.println("node1's count from map: " + nodeMap.get(node1).getCount()); 
    System.out.println(""); 

    nodeMap.put(node2, node2); 
    System.out.println("added node2 to hash map"); 
    System.out.println("hash map size: " + nodeMap.size()); 
    System.out.println("hash map entry set size: " + nodeMap.entrySet().size()); 
    System.out.println("hash map contains node1? " + (nodeMap.containsValue(node1) ? "true" : "false")); 
    System.out.println("hash map contains node2? " + (nodeMap.containsValue(node2) ? "true" : "false")); 
    System.out.println("hash map contains node3? " + (nodeMap.containsValue(node3) ? "true" : "false")); 
    System.out.println("node1's count from map: " + nodeMap.get(node1).getCount()); 
    System.out.println(""); 

    // note that if node4 is used then it replaces the value that stored node1 
    nodeMap.put(node3, node3); 
    System.out.println("added node3 to hash map"); 
    System.out.println("hash map size: " + nodeMap.size()); 
    System.out.println("hash map entry set size: " + nodeMap.entrySet().size()); 
    System.out.println("hash map contains node1? " + (nodeMap.containsValue(node1) ? "true" : "false")); 
    System.out.println("hash map contains node2? " + (nodeMap.containsValue(node2) ? "true" : "false")); 
    System.out.println("hash map contains node3? " + (nodeMap.containsValue(node3) ? "true" : "false")); 
    System.out.println("node1's count from map: " + nodeMap.get(node1).getCount()); 
} 

protected class Node { 

    private String data; 

    private Integer count; 

    public Node(String data, Integer count) { 
     this.data = data; 
     this.count = count; 
    } 

    @Override 
    public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     result = prime * result + getOuterType().hashCode(); 
     result = prime * result + ((data == null) ? 0 : data.hashCode()); 
     return result; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (this == obj) 
      return true; 
     if (obj == null) 
      return false; 
     if (getClass() != obj.getClass()) 
      return false; 
     Node other = (Node) obj; 
     if (!getOuterType().equals(other.getOuterType())) 
      return false; 
     if (count == null) { 
      if (other.count != null) 
       return false; 
     } 
     else 
      if (!count.equals(other.count)) 
       return false; 
     if (data == null) { 
      if (other.data != null) 
       return false; 
     } 
     else 
      if (!data.equals(other.data)) 
       return false; 
     return true; 
    } 


    public String getData() { 
     return data; 
    } 


    public void setData(String data) { 
     this.data = data; 
    } 


    public Integer getCount() { 
     return count; 
    } 


    public void setCount(Integer count) { 
     this.count = count; 
    } 

    private HashMapTest getOuterType() { 
     return HashMapTest.this; 
    } 

} 

}

它输出:

node1 hash: 1077170390 
node2 hash: 1077170391 
node3 hash: 1077170390 
node1 hash == node2 hash? false 
node2 hash == node3 hash? false 
node1 hash == node3 hash? true 
node1.equals(node2)? false 
node2.equals(node3)? false 
node1.equals(node3)? false 

added node1 to hash map 
hash map size: 1 
hash map entry set size: 1 
hash map contains node1? true 
hash map contains node2? false 
hash map contains node3? false 
node1's count from map: 1 

added node2 to hash map 
hash map size: 2 
hash map entry set size: 2 
hash map contains node1? true 
hash map contains node2? true 
hash map contains node3? false 
node1's count from map: 1 

added node3 to hash map 
hash map size: 3 
hash map entry set size: 3 
hash map contains node1? true 
hash map contains node2? true 
hash map contains node3? true 
node1's count from map: 1