每个集合的出现一定是为了解决某种问题的解决方案。
集合流程图
- JAVA中集合和数组的区别
- Collection和Collections的区别
- ArrayList和LinkedList 和Vector的区别
- list/set/map的区别
- HashSet和TreeSet和LinkedHashSet区别
- HashMap和Hashtable的比较
- HashMap和ConcurrentHashMap区别
- HashMap 底层实现原理
- HashMap和LinkedHashMap的区别?
- ArrayList/LinkedList /HashMap初始大小,add后是多少?(jdk1.8)
一、JAVA中集合和数组的区别
数组:
定义:相同数据类型的集合。
缺点:声明数组长度是固定的。
集合:
定义:相同数据类型的集合。
优点:声明时不需要指定长度。(底层做了动态扩容问题)
1. 数组声明了它容纳的元素的类型,集合默认是Object。
2. 数组一旦固定大小就无法改变容量,而集合是可以动态扩展容量。
二、Collection和Collections的区别
- Collection:是集合类的上级接口,继承与它的接口主要有Set、List
- Collcetions:针对集合类的一个帮助类,提供了一系列静态方法实现对各种集合的搜索、排序、线程安全等操作
三、ArrayList和LinkedList 和Vector的区别
类 别 | ArrayList | Vector | LinkedList |
数据结构 | 数组 | 数组 | 双向链表 |
优 点 | 查询快 | 查询快 | 增删快 |
缺点 | 增删慢 | 增删慢 | 查询慢 |
继 承 类 | AbstractList | AbstractList | AbstractSequentialList |
实 现 接 口 | List, RandomAccess,Cloneable, Serializable | List, RandomAccess, Cloneable, Serializable | List, Deque, Cloneable, Serializable |
线 程 安 全 | 不安全 | 被synchronized修饰,线程 安全 | 不安全 |
默 认 容 量 | 10 | 10 | |
最 大 容 量 | Integer.MAX_VALUE - 8 | Integer.MAX_VALUE - 8 | 1 << 25 |
扩 增 | 1.5倍,不可设增长因子 | 2倍,可设增长因子 | \ |
使 用 场 景 | 频繁查找元素(单线程) | 频繁查找元素(多线程) | 频繁增删元素(单线 程) |
1.线程安全
Vector : 线程安全
ArrayList, LinkedList : 线程不安全
2.实现⽅式
LinkedList : 链表,比基于数组更节省空间
ArrayList,Vector : 数组
3.扩容
ArrayList和Vector使⽤数组实现, 当数组长度不够,内部会创建⼀个更大的数组
LinkedList 不存在这⽅⾯的问题
4.速度
ArrayList 查改快, 增删慢
LinkedList 查改慢, 增删快
四、list/set/map的区别
list/set/map都是各自集合的接口。
本文中的有序指的是添加顺序和遍历顺序一致,称为有序。
类别 | list | set | map |
元素顺序 | 有序 | 无序 | 无序 |
元素去重 | 可以 | 不可以 | 键唯一,value可以重复 |
collection接口 | 继承 | 继承 | 并列 |
总结:
List:
1.可以允许重复的对象。
2.可以插入多个null元素。
3.是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。
4.常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。
Set:
1.不允许重复对象
2. 无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator 或者 Comparable 维护了一个排序顺序。
3. 只允许一个 null 元素
4.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。
Map:
1.Map不是collection的子接口或者实现类。Map是一个接口。
2.Map 的 每个 Entry 都持有两个对象,也就是一个键一个值,Map 可能会持有相同的值对象但键对象必须是唯一的。
3. TreeMap 也通过 Comparator 或者 Comparable 维护了一个排序顺序。
4. Map 里你可以拥有随意个 null 值但最多只能有一个 null 键。
5.Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)
五、HashSet和TreeSet和LinkedHashSet区别
类别 | HashSet | TreeSet | LinkedHashSet |
数据结构 | hash表 | 树 | 链表 |
元素顺序 | 无序 | 有序 | 有序 |
null值存在 | 一个 | 不可以 | 一个 |
时间复杂度 | 1 | n | 1 |
线程安全 | 不安全 | 不安全 | 不安全 |
HashSet:
1、无序 2、非线程安全 3、集合元素中可以存放一个null
TreeSet:
1、默认自然顺序的有序集合 2、非线程安全 3、不可以存放null元素
LinkedHashSet:
1、保存元素添加顺序的有序集合 2、非线程安全
六、HashMap和Hashtable的比较
类别 | HashMap | Hashtable |
父类 | AbstractMap | Dictionary |
遍历Iterator | fail-fast迭代器 | 1.8前:Enumeration |
线程 | 不安全 | 安全:Synchronize、modCount++ |
null值 | 可以 | 不可以 |
容量扩增 | 16、2:计算效率 | 11、2n+1:哈希冲突减少 |
方法 | / | 多elments() 和contains() 两个方法 |
1、HashTable 线程安全,HashMap 非线程安全
2、Hashtable 不允许 null 值(key 和 value 都不可以),HashMap 允许 null 值(key 和 value 都可以)。
3、两者的遍历方式大同小异,Hashtable 仅仅比 HashMap 多一个 elements 方法
七、HashMap和ConcurrentHashMap区别
类 别 | HashMap | ConcurrentHashMap |
底 层 结 构 | 1.8前:列表+链表 1.8:列表+链 表+红黑树(链表长度到8) | 1.7:数组+链表 1.8:数组+链表+红黑树 |
线 程 | 不安全 | 安全:分段锁、CAS+Synchronized |
扩 增 | 默认初始值16、扩容因子: 0.75(时间与空间一个平衡值), 扩容一倍 | 段内元素超过该段对应Entry数组长度的75%触发扩 容,不会对整个Map进行扩容 ConcurrentHashMap |
null 值 | 可以 | 不可以 |
总结:
1、ConcurrentHashMap是线程安全的,HashMap不是线程安全的
2、HashMap允许键和值为null,ConcurrentHashMap不允许
3、HashMap在用Iteroctor遍历的同时,不允许修改HashMap,ConcurrentHashMap允许该行为,并且对后续的遍历是可见的
(CurrentHashMap使用的是分段锁,效率高于HashTable,且是线程安全)
八、HashMap 底层实现原理
具体详细可参考:HashMap原理讲解
一、HashMap基本描述
HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。并且不保证映射的顺序。
1.1HashMap的数据结构?
哈希表结构(链表散列:数组+链表)实现,结合数组和链表的优点。当链表长度超过8时,链表转换为红黑树
1.2HashMap的工作原理?
HashMap(底层采用数组+链表),采用Entry数组来存储key-value对,每一个键值对组成了一个Entry实体,Entry类实际上是一个单向的链表结构,它具有Next指针,可以连接下一个Entry实体,依次来解决Hash冲突的问题,因为HashMap是按照Key的hash值来计算Entry在HashMap中存储的位置的,如果hash值相同,而key内容不相等,那么就用链表来解决这种hash冲突。
1.3HashMap的put实现过程?
HashMap通过put&get方法存储和获取。我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put(key, value)方法传递键和值时,它先调用key.hashCode()方法,得到hash值,然后结合数组长度,计算得数组下标,用于找到bucket位置,来储存Entry对象。
如果hash值在HashMap中不存在,则执行插入,若存在,则发生碰撞,则插入链表的尾部(尾插法)或者红黑树中(树的添加方式)。
如果hash值在HashMap中存在,且它们两者equals返回true,则更新键值对。
如果HashMap集合中的键值对大于12,调用resize方法进行数组扩容。
1.4HashMap的get实现过程?
从HashMap中get元素时,首先计算key的hashCode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。
底层的数据结构:HashMap的底层主要是基于数组和链表来实现的,它之所以有相当快的查询速度主要是因为它是通过计算散列码来决定存储的位置。
1.5 JDK8中什么时候会转为红黑树?
如果链表的长度超过了8,那么链表将转换为红黑树。(桶的数量必须大于64,小于64的时候只会扩容)。
九、HashMap和LinkedHashMap的区别?
LinkedHashMap是继承于HashMap,是基于HashMap和双向链表来实现的。
HashMap无序;LinkedHashMap有序,可分为插入顺序和访问顺序两种。如果是访问顺序,那put和get操作已存在的Entry时,都会把Entry移动到双向链表的表尾(其实是先删除再插入)。
LinkedHashMap存取数据,还是跟HashMap一样使用的Entry[]的方式,双向链表只是为了保证顺序。
LinkedHashMap是线程不安全的,HashMap不是线程安全的
十、ArrayList/LinkedList /HashMap初始大小,add后是多少?(jdk1.8)
类型 | ArrayList | LinkedList | HashMap |
默认 | []数据 0 | 0 | 16 |
扩容 | 1.5 | 无 | 0.75因子、2倍 |
最大 | Integer.MAX_VALUE - 8 | 无 | 1 << 30 |
ArrayList: jdk1.8之后:
1.ArrayList初始集合不初始化数组容量的时候,默认值为0
2.添加元素后,扩容为10,之后每次扩容为原来的0.5倍
LinkedList :
是一个双向链表,无初始大小,无扩容机制,直接添加即可
HashMap:
HashMap 初始化大小是 16 ,扩容因子默认0.75(可以指定初始化大小,和扩容因子)
扩容机制.(当前大小 和 当前容量 的比例超过了 扩容因子,就会扩容,扩容后大小为 一倍(*2)。