zoukankan      html  css  js  c++  java
  • 集合(3)—— Map

    一、概念

    严格来说Map并不是一个集合,而是两个集合的映射关系,这两个集合每条数据通过映射关系,形成了Entry<key,value>,我们可以看成一条数据,key作为键,value作为值,称为键值对。一个Map由多个Entry组成。

    因为Map不是Collection的子接口,所以没有Iterator,无法对其进行forEach遍历。

    二、Map的部分实现类

    HashMap

    采用哈希表算法,不会保证key的添加顺序,不允许重复,允许null值作为key,线程不安全。判断重复的标准:两个Entry先使用equals方法比较key,如果相同再比较key的hashCode,当两次判断都相同的时候认为是相同元素。

    TreeMap

    采用红黑树算法,不会保证key的添加顺序,不允许重复,不允许null值作为key,线程不安全,集合中的元素按照key的自然排序或定制规则进行排序,判断重复的标准是:compareTo/compare方法的返回值为0。

    LinkedHashMap

    采用链表和哈希表算法,保证元素的添加顺序,不允许重复,允许null值作为key,线程不安全,判断重复的标准和HashMap相同。

    HashTable

    线程安全的HashMap,不可以存放NULL,性能低。

    Properties

    HashTable的子类,要求key和value都是String类型,用于加载资源文件

    三、HashMap和HashSet的关系

    首先我们来看一下HashSet的源码:

     1 package collection;
     2  
     3 import java.util.AbstractSet;
     4 import java.util.HashMap;
     5 import java.util.Iterator;
     6 import java.util.Set;
     7  
     8 public class HashSet<E>
     9     extends AbstractSet<E>
    10     implements Set<E>, Cloneable, java.io.Serializable
    11 {
    12     //HashSet里封装了一个HashMap
    13     private  HashMap<E,Object> map;
    14  
    15     private static final Object PRESENT = new Object();
    16  
    17     //HashSet的构造方法初始化这个HashMap
    18     public HashSet() {
    19         map = new HashMap<E,Object>();
    20     }
    21  
    22     //向HashSet中增加元素,其实就是把该元素作为key,增加到Map中
    23     //value是PRESENT,静态,final的对象,所有的HashSet都使用这么同一个对象
    24     public boolean add(E e) {
    25         return map.put(e, PRESENT)==null;
    26     }
    27  
    28     //HashSet的size就是map的size
    29     public int size() {
    30         return map.size();
    31     }
    32  
    33     //清空Set就是清空Map
    34     public void clear() {
    35         map.clear();
    36     }
    37      
    38     //迭代Set,就是把Map的键拿出来迭代
    39     public Iterator<E> iterator() {
    40         return map.keySet().iterator();
    41     }
    42  
    43 }
    View Code

    可以发现,HashSet实际上是一个HashMap。

    只不过以存入的对象作为key值,所有的元素的value都是常量PRESENT。

    四、浅谈hashcode原理,分析HashMap,HashSet查找效率高的原因

    利用一种空间换时间的思维,存入时计算对象的hashcode值,然后存储到对应该值的位置,查找时通过对象的hashcode值直接定位获取,达到惊人的O(1)时间复杂度。

    简单的类比一下:

    -----hashcode概念-----
    所有的对象,都有一个对应的hashcode(散列值)
    比如字符串“gareen”对应的是1001 (实际上不是,这里是方便理解,假设的值)
    比如字符串“temoo”对应的是1004
    比如字符串“db”对应的是1008
    比如字符串“annie”对应的是1008

    -----保存数据-----
    准备一个数组,其长度是2000,并且设定特殊的hashcode算法,使得所有字符串对应的hashcode,都会落在0-1999之间
    要存放名字是"gareen"的英雄,就把该英雄和名称组成一个键值对,存放在数组的1001这个位置上
    要存放名字是"temoo"的英雄,就把该英雄存放在数组的1004这个位置上
    要存放名字是"db"的英雄,就把该英雄存放在数组的1008这个位置上
    要存放名字是"annie"的英雄,然而 "annie"的hashcode 1008对应的位置已经有db英雄了,那么就在这里创建一个链表,接在db英雄后面存放annie

    -----查找数据-----
    比如要查找gareen,首先计算"gareen"的hashcode是1001,根据1001这个下标,到数组中进行定位,(根据数组下标进行定位,是非常快速的) 发现1001这个位置就只有一个英雄,那么该英雄就是gareen.
    比如要查找annie,首先计算"annie"的hashcode是1008,根据1008这个下标,到数组中进行定位,发现1008这个位置有两个英雄,那么就对两个英雄的名字进行逐一比较(equals),因为此时需要比较的量就已经少很多了,很快也就可以找出目标英雄(但是我们需要尽量避免这种情况的发生,会影响到HashMap的性能)
    这就是使用HashMap进行查询,非常快的原理。

     

  • 相关阅读:
    HTTP 缓存
    css样式重置方案 -解决浏览器差异
    前端 网址收集
    最全前端资源汇集
    【收集】JAVA多文件 上传文件接口代码 -兼容app
    前端编码规范(4)—— CSS 和 Sass (SCSS) 规范
    前端编码风格规范(3)—— JavaScript 规范
    前端编码规范(2)—— HTML 规范
    前端编码规范(1)—— 一般规范
    【转载】jQuery插件开发精品教程,让你的jQuery提升一个台阶
  • 原文地址:https://www.cnblogs.com/blogforvi/p/11627011.html
Copyright © 2011-2022 走看看