ArrayList、LinkedList、Vector 比较

相同点:

  1. 都实现了 List<E> 接口,所以都是顺序容器
  2. 都实现了 Cloneable、Serializable 接口,可进行序列化和拷贝

不同点:

功能点ArrayListLinkedListVector(不推荐使用)
实现原理内部维护 Object[] 数组使用双向链表,内部维护头尾节点的引用内部维护 Object[] 数组
RandomAccess 接口
(快速访问策略,for 循环的方式获取数据会优于用迭代器 Iterator 获取数据)
实现了没有实现了
Deque<E>接口
(继承自 Queue<E> 接口,实现双向队列方法)
没有实现了,因此具有队列特性没有
是否线程安全不安全,引入了 fast-fail 机制不安全,引入了 fast-fail 机制1. 在一定程度上实现了线程安全。在方法上加了 synchronized 关键字,因为 synchronized 是 JVM 级的,所以不可修改、效率极低。
2. 对于复合操作而言,只是同步方法但并没有解决线程安全的问题。因为在两个原子操作之间存在间隙,在多线程环境中,完全有可能被其他线程获得 vector 的 lock 并改变其状态。要真正达成线程安全,还需要以 vector 对象为锁,来进行操作。所以用 vector 和 ArrayList 就没有区别了
操作特点1. 查询快,因为数组的内存空间地址是连续的
2. 增删慢,因为进行增删操作,经常会涉及到数组的移动复制、扩容复制等;数组长度是确定不能更改的,需要将原数组赋值到新数组。但是,如果是在结尾处的增删,不需要考虑长度情况下,还是很快的。
1. 增删快,因为链表的增删操作只需更改链接的 2 个链表引用,不需要像数组频繁创建复制
2. 查询慢,因为链表的存储地址不连续,查询需要通过引用循环访问
单线程情况下,与 ArrayList 相同。但是多线程环境下,效率极低,并且不是绝对安全。
内部特点1. 无参构造器时默认列表长度 0,第一次添加元素,增长为 10
2. 数组扩容时,首先判断扩容一半是否足够,若不够则直接扩容至结果长度(原长度+添加个数)
3. 数组最大容量,实际值为 2^31-1-8,超出会爆 OutOfMemoryError。数组除了存放数据外,还有一个 length 属性,减 8 为了存放数组长度
1. 移除节点时,将该节点前后引用、元素值引用置空,帮助 GC 回收1. 无参构造器时,默认的数组长度为 10,不是 0
2. Vector 扩容字段不是静态常量,而是在构造方法中指定的。若没有指定,在扩容时按照双倍扩容

栈(Stack)和队列(Queue)

  1. 都是 Collection 容器,栈是先进后出,队列是先进先出。他们的实现方式有 数组和链表 两种。
  2. 在 Java 中,栈有一个实现类,继承自 Vector 容器,底层用数组实现。Vector 在方法上加了 synchronized 锁,基本情况下线程安全,不过效率非常低,JDK 已经不推荐使用。
  3. 在 Java 中,队列是一个接口,有一个子类 Deque 双向队列。
  4. 目前 JDK 推荐使用的栈和队列是它的实现类 ArrayDeque, 基于数组实现的双向队列,线程不安全。它的效率要比 Stack 和 LinkedList 高。使用头尾双指针,循环数组的方式实现。
  5. 线程安全的通用栈和队列可以用 ConcurrentLinkedDeque,和更高级的阻塞队列 BlockingDeque 实现类。

List、Set、Map 比较

ListSetMap
有序无序无序
可以有重复对象不允许存在重复对象键对象不可以重复,值对象可以重复
单列数据单列数据键值对,双列数据

HashMap、TreeMap

对比项目HashMapTreeMap
内部结构数组+链表+红黑树红黑树
继承关系继承 AbstractMap,实现 Map 接口继承 AbstractMap,实现 NavigableMap、SortedMap
保证了 SortedMap 的有序性
实现方式定义了 hashcode() 和 equals(),基于 hash 实现,可以根据初始容量和负载因子调优红黑树总是处于平衡的状态,无法调优
遍历顺序不能保证遍历顺序,因为 key 的 hash 值跟 hashcode 和表长度都有关系。会按照排序后的顺序输出
长度限制一个桶内链表达到 8 时转化为红黑树,表长最大为 Integer.Max红黑树没有长度限制
场景通常情况下,HashMap 是要更快一点,毕竟数组嘛需要排序才使用 TreeMap