集合关系图
Collection
集合共有的父类接口 ,包含集合的共性方法:add、remove、Iterator、contains、clear…
迭代器 Iterator
它的作用是将各种不同集合的“判断”与“取出”操作封装成一个对象。每种集合都可以使用迭代器Iterator的hasNext/next/remove 来判断和取出集合中的对象。
List
元素是有序的,并且可以重复;该集合有索引。add(index,element)、remove(index)、set(index,element)、 get(index)、indexOf(element)、subList(from,to)…
ListIterator:List迭代器,是Iterator的子类,继承了Iterator的所有方法,并有 add\set\nextIndex等对list操作的方法。
PS:如果List需要使用Collections工具类的sort排序方法,泛型的对象必须实现Comparable接口。或者另外创建一个比较类,实现Comparator接口。
ArrayList
- 底层的数据结构使用的是数组结构;
- 特点:查询速度快; 线程不同步。
- 初始容量为10,当超过容量时,则新建一个新的数组,长度为原始长度+(50%+1);
LinkedList
- 底层的数据结构使用的是链表结构;
- 特点:增、删、改的速度快;
Vector:
- 底层是数组结构,该类型是在Java1.0出现的,而集合是在Java1.2出现的。
- 使其实现List接口的同时,线程同步;
- 初始容量为10,当超过容量时,则新建一个新的数组,长度为原始长度*2;(已被淘汰)
Set特点:
元素是无序的,并且不可以重复;
HashSet
- 底层数据结构为哈希表;
- 特点:在执行增删改查的时候,首先都是先判断集合中对象中的hashcode方法,判断hash值是否相同。
TreeSet
- 底层数据结构是二叉树;
- 可以对Set集合中的元素进行字母排序;
- 若存入自定义对象,对象需要实现Comparable接口的compareTo方法,实现自然比较。
Map
键值对的存储,键唯一;基本方法:put(K key, V value)、clear()、 remove(K key)、containsValue(Object value)、contailsKey(Object key)、isEmpty()、get(Object key)、size()、values()、entrySet()、keySet()。。。
HashMap
- 底层是哈希表的数据结构;
- null值允许作为键或值存入。
- 初始化容量16,加载因子0.75
- 线程不安全,效率高
Hashtable
- 底层是哈希表的数据结构,该哈希表将键映射到相应的值
- 任何非null对象都可以用作键或值
- PS:用作键的对象必须实现HashCode方法和equals方法
- 线程安全,效率低
TreeMap:
- 底层是二叉树数据结构;
- 线程不同步;
- 可以对集合中的键进行排序。
HashMap的实现原理***
HashMap的实现原理,在JDK1.7的时候,使用的是 数组 + 链表实现。而JDK1.8之后, 为了提高遍历效率,将链表改成了红黑二叉树的数据结构;
put流程如下
- 获取key值的hashCode
- 用hashCode % size 确定数组位置 index
- 在指定位置中,如果为null,则直接添加
- 若不为null,遍历链表匹配是否存在相同hashCode,若存在,则替换value
- 若不存在,则在链头插入新的value
- 常量size自增
PS:在第1步获取key值的hashCode之前,会判断key是否为null,若为null,默认放到数组第一位table[0]里。
get流程如下
- 获取key值的hashCode
- 用hashCode % size 确定数组位置 index
- 在指定位置中,如果为null,直接返回
- 若数组不为null,则使用equals()函数匹配value返回
Map在JDK1.7之前的数据结构:
JDK1.8之后,为了避免因hash算法导致数组某个节点积累的链表过长,JDK1.8修改成“当数组某个点位的链表长度超过8时,则修改成红黑树结构”
扩容
初始化长度为16,加载因子为0.75;即当前长度 > 16 * 0.75 时,进行扩容。扩容的长度为 *2;再将原有的值重新hashing,放入新的数组中。
线程安全Map
常用的有Hashtable、ConcurrentHashMap两个。两者的区别如图:
Hashtable对整个数组都进行锁处理,这样极大地影响性能;
而ConcurrentHashMap的实现可以对hashing之后的值相同的数组的点位进行锁处理,极大地提高效率的同时,保证线程安全。