接口Map的方法介绍及其底层的实现

一、方法 Map是一个键值对结构的数据类型
key:我们要通过key去找我们对应的值
value:我们存放的具体信息
我们存储的信息都是以key作为标识,所以key不能重复
如果key信息重复,后面会把前面的给覆盖掉

增:put ( K key , V value ) :添加一个元素进入Map类对象末尾;因为元素的关键字是唯一的,当使用put方法的时候,该方法会将所添加元素,按照他所对应的关键字,添加到对应关键字位置,并覆盖原有权值,这时候,put方法就会把原有的对应该关键字的权值返回回来。
【接口Map的方法介绍及其底层的实现】putAll ( Maps < ? extends K , ?extends V > m) :将另一个Map类型对象添加至调用他的对象的末尾;
删:clear ( ) :清空调用该函数的Map类对象;
remove ( Object k ) :移除关键字为k的元素;
改:put即可实现;
查:get ( Object k ) :获取对应关键字为k值的元素;这里需要注意一点的是,我们可以通过个get方法来判断对应的Map类对象是否存在,当然,这种判断方法用在对应的Hashtable类当中是最合适的,因为该类不会出现赋值为空的情况。但是,这并不表示着这种判断存在的方法只能用在Hashtable类中,在大多数情况下,我们都是将这种方法放在HashMap类中使用的,因为,实际上赋值为空的情况是没有意义的一般很少出现
size ( ) :获取调用该函数的Map类对象的大小;
value ( ) :返回调用他的Map类对象关于其中元素权值的一个Collection类对象,这个函数的作用就是为了拿值;
set keySet ( ) :返回调用该方法的Map类对象的关键字的Set类视图;
set >entrySet ( ) :返回调用该方法的Map类对象的元素映射关系的Set类视图,而这个关系的数据类型就是Map.Entry< k, v>;
判断:containValue ( Object v ) :判断调用该函数的类中是否有权值为v的元素;
containKey ( Object k ) :判断调用该函数的类中是否有关键字为k的元素;
isEmpty ( ) :继承自Object的通用方法。
这里面我们需要强调的是两个方法,一个是entrySet,另一个是keySet。


  1. //首先是keySet使用思想举例:
  2. sop("keySetcondition:");
  3. Set set =map.keySet();
  4. Iterator ite =set.iterator();
  5. for(String key; ite.hasNext(); key= ite.next())
  6. {
  7. sop("key:"+key+""+"value:"+map.get(key));
  8. }
  9. //然后我们来看一下entryKey的使用思想
  10. sop("entrySetcondition:");
  11. Setset = map.entrySet();
  12. Iteratorite = set.iterator();
  13. for(Map.Entryen; ite.hasNext(); en=ite.next())
  14. {
  15. String key = en.getKey();
  16. String value =https://www.it610.com/article/en.getValue();
  17. sop("key:"+key+""+"value:"+value);
  18. }
  19. }
  20. public static void sop(Object obj)
  21. {
  22. System.out.println (obj);
  23. }


二、底层实现 /**
* Map
* 创建对象
* //默认的初始容量16
* static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
* //默认的使用的大小是总大小的75%
* static final float DEFAULT_LOAD_FACTOR = 0.75f;
* //map中数组可用的大小
* int threshold;
* //map中数组存放数据大小
* int size;
* //创建对象的时候默认创建一个空的entry数组
* transient Entry[] table = (Entry[]) EMPTY_TABLE;
* 存放数据
* 第一次存放数据
* 首先检查数组是不是默认的,如果是第一次需要创建一个新的
* 新创建的数组是entry类型的,大小为16,可用为12
* 计算key的hash值,相对是唯一的
* 然后根据数组的大小计算当前key所应该处于的索引位置
* 然后创建新的entry将数据存放至数组
* 第一次之后加入数据
* 首先计算key对应的hash值,算出对应的位置索引
* 判断当前key有没有指定值,
* 如果已经存在值
* 就会把原来的值返回,并且新的value覆盖掉原来的值
* 如果已经不存在值
* 我们还需要判断当前数组容量是否足够
* 扩容大小为原来的两倍,可用的大小也为原来的两倍,总大小的0.75
* 最后将其存放至容器
* 取出数据
* 首先判断map是否为空,为空直接null
* 不为空,计算当前key的hash值,然后计算索引值
* 取出map的数组中指定位置的entry,然后进行比较
* 比较当前对象,如果当前对象不equals,开始比较单向链表中的entry
* 比较的时候先比较hash && 如果hash都不一样,对象肯定不一样,提高效率
*
* 为什么map数组的大小只允许使用75%
* 假如数组用满,他并不是将数组的每个索引全部占用
* 当我们用对象的hash值去&数组大小的时候,不避免会产生相同的索引
* 这样就会导致一个索引有可能存放两个不同key,这个时候使用单向链表解决
* 首先数组索引指向新创建的entry,新entry有一个next属性会指向原来的entry对象,形成一个单向链表
* 其实如果使用单向链表存储数据的时候,已经违背了map设计的思想
* 所以我们最好重写每一个对象的hashcode方法
* 当我们的map里面的数组进行扩容的时候,当扩容完毕,首先散列我们现有存储的对象,尽量吧存在链表的地方给分开,提高查询效率
*
* Entry:记录
* 我们map为了存放数据,所以专门创建的一个静态内部类
* 类似于我们数组中的一个元素
* entry里面有两个属性
* key
* value
* 另外为了避免一些问题:不同hash算出相同index
* next:
* 另外为了查找更加的快捷,专门记录了key的hash值
* hash:比较的时候线比较hash值
*
* hashmap中可以存放空值



    推荐阅读