博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【jdk源码学习】HashMap
阅读量:6934 次
发布时间:2019-06-27

本文共 5972 字,大约阅读时间需要 19 分钟。

1 package com.emsn.crazyjdk.java.util;   2    3 /**  4  * “人”类,重写了equals和hashcode方法...,以id来区分不同的人,你懂的...  5  *   6  * @author emsn1026  7  *  8  */   9   10 public class Person {  11       12     /** 13      * 身份id 14      */  15     private String id;  16       17     /** 18      * 姓名 19      */  20     private String name;  21   22     public String getId() {  23         return id;  24     }  25   26     public void setId(String id) {  27         this.id = id;  28     }  29   30     public String getName() {  31         return name;  32     }  33   34     public void setName(String name) {  35         this.name = name;  36     }  37   38     @Override  39     public int hashCode() {  40         final int prime = 31;  41         int result = 1;  42         result = prime * result + ((id == null) ? 0 : id.hashCode());  43         return result;  44     }  45   46     @Override  47     public boolean equals(Object obj) {  48         if (this == obj)  49             return true;  50         if (obj == null)  51             return false;  52         if (getClass() != obj.getClass())  53             return false;  54         Person other = (Person) obj;  55         if (id == null) {  56             if (other.id != null)  57                 return false;  58         } else if (!id.equals(other.id))  59             return false;  60         return true;  61     }  62   63     @Override  64     public String toString() {  65         return "Person [id=" + id + ", name=" + name + "]";  66     }  67       68 }

新建一个Person类,重写其中的equals和hashcode方法。这样,同样id的人会被认为是同样的事例,不同id的即时姓名相同也是不同的人,把Person类的实例作为HashMap的key时,key的唯一性讲通过Person实例的id来控制.

package com.emsn.crazyjdk.java.util;    import java.util.HashMap;  import java.util.Map;  import java.util.Map.Entry;    import com.emsn.crazyjdk.java.util.Person;    /**  * @author emsn1026  *  */  public class MapTest {        /**      * @param args      */      public static void main(String[] args) {              Map m = new HashMap();              Person p1 = new Person();              Person p2 = new Person();                            p1.setId("1");              p1.setName("name1");              p2.setId("1");              p2.setName("name2");                                    m.put(p1, "person1");              m.put(p2, "person2");                            System.out.println("Map m's size :" + m.size());                            for(Object o :m.entrySet()){                  Entry e = (Entry)o;                  System.out.println("key:"+ e.getKey());                  System.out.println("value:"+ e.getValue());              }                        }    }

打印的结果是 

Map m's size :1 
key:Person [id=1, name=name1] 
value:person2 

可见key已存在,value被覆盖,这个结果可以预测。那么接下来我们把代码修改下: 

package com.emsn.crazyjdk.java.util;    import java.util.HashMap;  import java.util.Map;  import java.util.Map.Entry;    import com.emsn.crazyjdk.java.util.Person;    /**  * @author emsn1026  *  */  public class MapTest {        /**      * @param args      */      public static void main(String[] args) {              Map m = new HashMap();              Person p1 = new Person();              Person p2 = new Person();                            p1.setId("1");              p1.setName("name1");              p2.setId("2");              p2.setName("name2");                                    m.put(p1, "person1");              m.put(p2, "person2");                            System.out.println("Map m's size :" + m.size());                            p2.setId("1");                            System.out.println("Map m's size :" + m.size());                            for(Object o :m.entrySet()){                  Entry e = (Entry)o;                  System.out.println("key:"+ e.getKey());                  System.out.println("value:"+ e.getValue());              }                        }    }

 此处的变化是将p1,p2的id设成不同,然后都作为key插入map,因为两个key不相同,所以我们的预测是都可以插入,此时map的size应该为2,待插入后我们修改p2的id为1,即与p1相同,这样就造成了两个entry的key相同的情况,测试再查看map的结构,看看是不是还是刚才插入的两项。 

    此时我们不知道HashMap的内部实现,所以我们不知道它的实例会不会在数据插入后还继续维持key的唯一性。 
    我们可以猜测的是三种答案: 
    1.抛出异常,不允许修改p2的id与p1相同,维护key的唯一性; 
    2.可以修改,但根据某种算法删除p1或p2中的一项,也能起到维护key的唯一性; 
    3.可以修改,没有任何事情发生....两项id相同的person实例并存于map中,即存在同一个key对应了两个value。 
    那么各位在没尝试并且没有查看过HashMap的源代码时会做出怎样的选择呢? 

 结果打印如下: 

Map m's size :2 
key:Person [id=1, name=name2] 
value:person2 
key:Person [id=1, name=name1] 
value:person1 
    那么是预测的第三种情况...这原本不是我最看好的答案..这样我就有一个疑问了,既然可以有两个相同的key对应不同的value存在,那么我通过这个key应该拿到的value是哪个呢?在上述代码的main方法末尾加入以下两行代码: 

System.out.println("Map m 通过get方法用key p1:"+p1+"时,获取的value:"+m.get(p1));  System.out.println("Map m 通过get方法用key p2:"+p2+"时,获取的value:"+m.get(p2));

得到的结果如下: 

Map m 通过get方法用key p1:Person [id=1, name=name1]时,获取的value:person1 
Map m 通过get方法用key p2:Person [id=1, name=name2]时,获取的value:person1 

可见不论你使用p1还是p2,得到的value都是person1。 

/**    *jdk中get方法的源码     * Returns the value to which the specified key is mapped in this identity     * hash map, or null if the map contains no mapping for this key.     * A return value of null does not necessarily indicate     * that the map contains no mapping for the key; it is also possible that     * the map explicitly maps the key to null. The     * containsKey method may be used to distinguish these two cases.     *     * @param   key the key whose associated value is to be returned.     * @return  the value to which this map maps the specified key, or     *          null if the map contains no mapping for this key.     * @see #put(Object, Object)     */    public V get(Object key) {if (key == null)    return getForNullKey();        int hash = hash(key.hashCode());        for (Entry
e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value;//--关键在这里。 } return null; }

如果一个Key对应2个Value。 他按顺序找到后,直接就 Return a.value了。而不会循环Person2.

 

转载于:https://www.cnblogs.com/dream-to-pku/p/6268119.html

你可能感兴趣的文章
Quartz安装包中的15个example
查看>>
12C -- DDL日志
查看>>
消息总线VS消息队列
查看>>
Eclipse SDK构建J2EE开发环境
查看>>
入门基础
查看>>
object dection资源
查看>>
Swift标识符和keyword
查看>>
【树莓派】【转载】基于树莓派,制作家庭媒体中心+下载机
查看>>
spring中InitializingBean接口使用理解
查看>>
strncmp函数——比较特定长度的字符串
查看>>
EF使用Fluent API配置映射关系
查看>>
输入页制作笔记
查看>>
C#使用xpath简单爬取网站的内容
查看>>
Id选择器和Class选择器
查看>>
人本质要好,要善良,要真诚,有格局和胸怀,有能力,有眼光,能讲故事,能找到人,能搞到钱...
查看>>
linux 磁盘性能监控
查看>>
CreateJs入门必知必会
查看>>
Spark Scala语言学习系列之完成HelloWorld程序(三种方式)
查看>>
SDL2源代码分析8:视频显示总结
查看>>
JavaScript中Object的总结
查看>>