1.说一说常用的集合
— List 有序,可重复
ArrayList
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程不安全,效率高
Vector
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程安全,效率低
LinkedList
优点: 底层数据结构是链表,查询慢,增删快。
缺点: 线程不安全,效率高
—Set 无序,唯一
HashSet
底层数据结构是哈希表。(无序,唯一)
如何来保证元素唯一性?
1.依赖两个方法:hashCode()和equals()
LinkedHashSet
底层数据结构是链表和哈希表。(FIFO插入有序,唯一)
1.由链表保证元素有序
2.由哈希表保证元素唯一
TreeSet
底层数据结构是红黑树。(唯一,有序)
- 如何保证元素排序的呢?
自然排序
比较器排序
2.如何保证元素唯一性的呢?
根据比较的返回值是否是0来决定
—Map无序的,键不允许重复,值允许重复
HashMap
基于 hash 表的 Map 接口实现,非线程安全,高效,支持 null 值和 null
键;
HashTable
线程安全,低效,不支持 null 值和 null 键;
LinkedHashMap
是 HashMap 的一个子类,保存了记录的插入顺序;
TreeMap
能够把它保存的记录根据键排序,默认是键值的升序排序
在集合中常见的数据结构(掌握)
ArrayXxx:底层数据结构是数组,查询快,增删慢
LinkedXxx:底层数据结构是链表,查询慢,增删快
HashXxx:底层数据结构是哈希表。依赖两个方法:hashCode()和 equals()
TreeXxx:底层数据结构是二叉树。两种方式排序:自然排序和比较器排序
2.针对Collection集合我们到底使用谁呢?
唯一吗?
是:Set
排序吗?
是:TreeSet
否:HashSet
如果你知道是Set,但是不知道是哪个Set,就用HashSet。
否:List
要安全吗?
是:CopyOnWriteArrayList或者Vector
否:ArrayList或者LinkedList
查询多:ArrayList
增删多:LinkedList
如果你知道是List,但是不知道是哪个List,就用ArrayList。
我们需要存放键值对时就选用 Map 接口下的集合,需要排序时选择 TreeMap,不需要排序时就选择 HashMap,需要保证线程安全就选用 ConcurrentHashMap。
3. 集合框架底层数据结构总结
3.1. List
Arraylist: Object[]数组
Vector:Object[]数组
LinkedList: 双向链表(JDK1.6 之前为循环链表,JDK1.7 取消了循环)
3.2. Set
HashSet(无序,唯一): 基于 HashMap 实现的,底层采用 HashMap 来保存元素
LinkedHashSet:LinkedHashSet 是 HashSet 的子类,并且其内部是通过 LinkedHashMap 来实现的。
TreeSet(有序,唯一): 红黑树(自平衡的排序二叉树)
3.3. Map
HashMap: JDK1.8 之前 HashMap 由数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。JDK1.8 以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间
LinkedHashMap: LinkedHashMap 继承自 HashMap,底层是数组和链表或红黑树。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
Hashtable: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
TreeMap: 红黑树(自平衡的排序二叉树)
4.为什么要使用集合?用数组不行吗?
- 数组的缺点是一旦声明之后,长度就不可变了;
- 声明数组决定了该数组存储的数据类型,集合提高了数据存储的灵活性,Java 集合不仅可以存储不同类型的对象,还可以保存具有映射关系的数据。
5.迭代器 Iterator 是什么?
Iterator 对象称为迭代器,迭代器可以对集合进行遍历,主要有hasNext() (集合中是否还有元素)和 next()(获得集合中的下一个元素) 方法,但每一种集合内部的数据结构不尽相同,它提供了统一的方法来遍历不同容器对象,而又不需要暴露该对象的内部细节。
迭代器更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException 异常。
6.有哪些集合是线程不安全的?怎么解决呢?
1.1.7. 有哪些集合是线程不安全的?怎么解决呢?
我们常用的 Arraylist ,LinkedList,Hashmap,HashSet,TreeSet,TreeMap, PriorityQueue 都不是线程安全的。可以使用线程安全的集合来代替。
如果你要使用线程安全的集合的话, java.util.concurrent 包中提供了很多并发容器供你使用:
ConcurrentHashMap: 可以看作是线程安全的 HashMap
CopyOnWriteArrayList:可以看作是线程安全的 ArrayList,在读多写少的场合性能非常好,远远好于 Vector.
ConcurrentLinkedQueue:高效的并发队列,使用链表实现。可以看做一个线程安全的 LinkedList,这是一个非阻塞队列。
BlockingQueue: 这是一个接口,JDK 内部通过链表、数组等方式实现了这个接口。表示阻塞队列,非常适合用于作为数据共享的通道。
ConcurrentSkipListMap :跳表的实现。这是一个Map,使用跳表的数据结构进行快速查找。
7.Arraylist 与 LinkedList 区别?
1.数据结构上,ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.是否支持快速随机访问,LinkedList 不支持高效的随机元素访问,而 ArrayList 支持。
3.对于新增和删除操作,LinedList比较占优势,因为ArrayList要移动数据。 不过ArrayList的插入,删除操作也不一定比LinkedList慢,如果在List靠近末尾的地方插入,那么ArrayList只需要移动较少的数据,而LinkedList则需要一直查找到列表尾部,反而耗费较多时间。
4.使用场景:
(1)如果应用程序对数据有较多的随机访问,ArrayList对象要优于LinkedList对象;
( 2 ) 如果应用程序有更多的插入或者删除操作,较少的数据读取,LinkedList对象要优于ArrayList对象;