(本人第一次写博客,部分内容有参照李刚老师的疯狂java系列图书,如有遗漏错误,请多指教,谢谢。)

Java的集合类可分为Set、List、Map、Queue,其中Set、List、Queue都有共同的接口:Collection.

所以Collection和Map是Java集合框架的根接口。Java集合实际上并不是真的把对象放入其中,集合中保存的只是对象的引用。

这里首先讲Map,因为所有的Set底层都是由Map实现的,仔细观察API可以发现,Set集合继承体系中所有的接口、实现类的类名,对应的Map集合体系都有。

如:Set-->Map

  EnumSet-->EnumMap

  SortedSet-->SortedMap

  TreeSet-->TreeMap

  NavigableSet-->NavigableMap

  HashSet-->HashMap

  LinkedHashSet-->LinkedHashMap

所不同的是,Map集合体系中还包括IdetityHashMap、WeakHashMap、Hashtable、Properties实现类。

Map集合用于保存具有映射关系的数据,其本质就是一个Object类型的动态数组,数组元素是Map接口的内部类Entry。

内部类Entry封装了一个key-value对。

key和value存在单向的一对一关系,通过指定的key总能找到唯一的确定的value.

由于这个特征,就必须要求Key是不可重复的,符合Set的特征。事实上,Map中所有的key就组成了一个Set集合。

而Value是可以重复的。只能通过key查询value,可以把value看作key的附庸。

一、HashMap 和 Hashtable

Hashtable较为古老,是HashMap的线程安全形式。其中封装了许多古老的方法,与HashMap主要有两点区别:

1、HashMap线程不安全,Hashtable线程安全,所以HashMap性能更好。

  而实现线程安全用集合工具类Collections的静态方法synchronizedMap()包装一下,更简单、实用。

2、Hashtable不允许使用null作为key和value,会引发NullPointerException异常,而HashMap允许。

HashMap的底层是数组实现的,其数组元素为一个Entry链表(栈)。

存储过程:根据元素的hashCode()返回值计算元素在数组中的存储索引。根据元素equals方法来计算元素在Entry链表中的存储位置。

  若有2个元素hashCode()返回值相同而equals为false,那么发生哈希冲突。新增加的Entry总放在Entry链表栈顶。

  HashMap底层数组默认大小为16,这种存储位置又叫做桶(bucket),默认负载极限为0.75,即当HashMap中填满3/4时,

  HashMap的容量将自动增加一倍。这个过程中,元素会重新分配,放入新的桶中。这个过程叫做rehashing.

 public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}

HashMap的put方法源代码

  static int indexFor(int h, int length) {
return h & (length-1);
}

索引的计算方法

  可以看到:1、元素的hash值是根据key的hashCode计算的。

       2、索引是根据元素的hash值简易计算的。

查询过程:与存储过程类似,先根据hashCode()返回值计算数组索引,若数组所在位置已经有元素,与栈中所有元素equals比较,若相同,则返回。

  public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry<K,V> 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;
}

HashMap的get方法

  所有参与计算hashCode()返回值的关键属性,都应用于作为equals()比较的标准。

  不应该给equals()和hashCode()方法的依赖属性提供注入方法,或者可以直接将其设置为final.

创建过程:除了默认的构造方法,HashMap还提供了指定初始容量、负载因子的构造器。

 public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
// Find a power of 2 >= initialCapacity
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1; this.loadFactor = loadFactor;
threshold = (int)(capacity * loadFactor);
table = new Entry[capacity];
init();
}

HashMap构造方法源代码

  可以看到:1、初始容量最大为1<<30。不可以更大。

       2、初始容量必须为大于指定容量的最小的2的n次方值

二、TreeMap

TreeMap采用“红黑树”的排序二叉树来保存Map中的每个Entry。每个Entry为红黑树的一个节点。

所有的Entry总是根据key按指定的规则保持有序。

红黑树是一种自平衡二叉树,每个节点的值都大于或等于它的左子树中所有节点的值,都小于或等于它的右子树中所有节点的值。

三、WeakHashMap、IdentityHashMap

WeakHashMap每个key对象保存了实际对象的弱引用。

IdentityHashMap的实现机制与HashMap类似,只有当key1==key2时,才认为key1与key2相等。它不保证任何key-value对之间的顺序,

也不保证它们的顺序随时间的推移不变。

四、LinkedHashMap、Properties

LinkedHashMap是HashMap的子类,使用双向链表来维护entry的插入次序,迭代输出时,元素顺序与插入顺序一致。

Properties也是HashMap的子类,把Map对象和属性文件关联起来,把Map对象的key和value与属性文件的属性名和属性值关联起来。

五、EnumMap

1、EnumMap所有key必须是枚举类的枚举值。

2、在内部以数组实现,根据key自然排序。

3、不允许使用null作为key,允许使用null作为value

4、创建EnumMap时必须指定一个枚举类,将EnumMap与指定枚举类关联起来。

5、EnumMap是性能最好的Map

另:Map有一个values方法,返回一个集合对象,

  其实,这个Values集合对象并未盛装任何java对象,主要用来遍历map中的所有value值。

Map集合 总结的更多相关文章

  1. Java版本:识别Json字符串并分隔成Map集合

    前言: 最近又看了点Java的知识,于是想着把CYQ.Data V5迁移到Java版本. 过程发现坑很多,理论上看大部分很相似,实践上代码写起来发现大部分都要重新思考方案. 遇到的C#转Java的一些 ...

  2. Java常用的几种集合, Map集合,Set集合,List集合

    Java中  Object是所有类的根 Java集合常用的集合List集合.Set集合.Map集合 Map接口常用的一些方法 size() 获取集合中名值对的数量 put(key k, value v ...

  3. Map集合

    1:Map (1)将键映射到值的对象. 一个映射不能包含重复的键:每个键最多只能映射到一个值. 键值对的方式存在 (2)Map和Collection的区别? A:Map 存储的是键值对形式的元素,键唯 ...

  4. MyBatis的一系列问题的处理(遍历Map集合和智能标签和属性和字段不一样的解决办法 和sql片段)(三)

    一.字段名与属性名(数据库的名字)不一样怎么办? 方案一:在小配置中配置一个resultMapper <!--方案一:resultMapper 字段名与属性名不一致 --> <res ...

  5. Map集合及与Collection的区别、HashMap和HashTable的区别、Collections、

    特点:将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值. Map集合和Collection集合的区别 Map集合:成对出现 (情侣)                       ...

  6. java://Comparator、Comparable的用法(按照要求将map集合的键值对进行顺序输出)

    import java.util.*; public class Person implements Comparable<Person>//使Person的属性具有比较性 { priva ...

  7. Java集合类学习笔记(Map集合)

    Map用于保存具有映射关系的数据,因此Map集合里保存着两组数据,一组用于保存Map的key,一组用于保存key所对应的value. Map的key不允许重复. HashMap和Hashtable都是 ...

  8. java学习第18天(map集合)

    Map集合是将键映射到值的对象.一个映射不能包含重复的键:每个键最多只能映射到一个值. 存储的是键值对形式的元素,键唯一,值可以重复,有点类似于数据库中的主键加数据.主要功能有: A:添加功能 put ...

  9. Map集合的应用及其遍历方式

    ---> HashMap :底层基于哈希表      存储原理也使用哈希表来存放的:            往HashMap添加了元素 ,首先会调用键的hashCode方法 获得一个哈希值,然后 ...

随机推荐

  1. thinkphp5命名规范

    类的命名采用驼峰法,并且首字母大写.如:User.UserType[不需要加后缀.如IndexController是没必要的,应当直接为Index.接口或者抽象类也保持这个规范] 属性命名采用驼峰法, ...

  2. Play Framework 完整实现一个APP(二)

    1.开发DataModel 在app\moders 下新建User.java package models; import java.util.*; import javax.persistence. ...

  3. [整理]PHP/HTML混写的四种方式

    PHP作为一款后端语言,为了输出给浏览器让浏览器呈现出来,无可避免的要输出HTML代码,下文介绍下我用过的三种PHP/HTML混编方法 1.单/双引号包围法 这是最初级的方法了,用法就像下面这样 &l ...

  4. Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作

    2 Mongodb CRUD 操作 Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作Mongodb Manual阅读笔记:CH3 数据模型(Data Models)Mong ...

  5. Xcode同时兼容Xcode7和Xcode8,两个版本并存,也适用于先升8再安装7

    先吐槽一下之前看到的一个教程,如下: 先在应用程序内,拷贝一份之前的xcode,然后再安装新版本,发现这种安装完成就是在之前上面迭代了  有木有?等于没任何作用 我这边就是不小心先升级了8,然后再安装 ...

  6. x01.os.9: 进程切换

    进入内核后,当然不能无所事事.先创建三个进程,分别打印 A,B,C.虽然只是简单的打印,但却是一切扩展的基础,不可等闲视之. 进程切换,涉及一系列的寄存器需要保护,于是,就有了 ProcessStac ...

  7. 网友转发的很全的 LISTCTL 控件使用的说明

    作者:lixiaosan 时间:04/06/2006 以下未经说明,listctrl默认view 风格为report 相关类及处理函数 MFC:CListCtrl类 SDK:以 "ListV ...

  8. 002.ICMP--拼接ICMP包,实现简单Ping程序(原始套接字)

    一.大致流程: 将ICMP头和时间数据设置好后,通过创建好的原始套接字socket发出去.目的主机计算效验和后会将数据原样返回,用当前时间和返回的数据结算时间差,计算出rtt. 二.数据结构: ICM ...

  9. 远程连接mysql报错【1130 -host 'localhost' is not allowed to connect to this mysql server】

    远程连接mysql时包如下错误: 1130 -host 'localhost' is not allowed to connect to this mysql server 解决办法 本地用root账 ...

  10. Java入门(二)——果然断更的都是要受惩罚的。。。

    断更了一个多月,阅读量立马从100+跌落至10-,虽说不是很看重这个,毕竟只是当这个是自己的学习笔记,但有人看,有人评论,有人认同和批评的感觉还是很巴适的,尤其以前有过却又被剥夺的,惨兮兮的. 好好写 ...