ArrayList、LinkedList、Vector 比较
相同点:
- 都实现了
List<E>
接口,所以都是顺序容器 - 都实现了
Cloneable、Serializable
接口,可进行序列化和拷贝
不同点:
功能点 | ArrayList | LinkedList | Vector(不推荐使用) |
---|---|---|---|
实现原理 | 内部维护 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)
- 都是 Collection 容器,栈是先进后出,队列是先进先出。他们的实现方式有 数组和链表 两种。
- 在 Java 中,栈有一个实现类,继承自 Vector 容器,底层用数组实现。Vector 在方法上加了 synchronized 锁,基本情况下线程安全,不过效率非常低,JDK 已经不推荐使用。
- 在 Java 中,队列是一个接口,有一个子类 Deque 双向队列。
- 目前 JDK 推荐使用的栈和队列是它的实现类 ArrayDeque, 基于数组实现的双向队列,线程不安全。它的效率要比 Stack 和 LinkedList 高。使用头尾双指针,循环数组的方式实现。
- 线程安全的通用栈和队列可以用 ConcurrentLinkedDeque,和更高级的阻塞队列 BlockingDeque 实现类。
List、Set、Map 比较
List | Set | Map |
---|---|---|
有序 | 无序 | 无序 |
可以有重复对象 | 不允许存在重复对象 | 键对象不可以重复,值对象可以重复 |
单列数据 | 单列数据 | 键值对,双列数据 |
HashMap、TreeMap
对比项目 | HashMap | TreeMap |
---|---|---|
内部结构 | 数组+链表+红黑树 | 红黑树 |
继承关系 | 继承 AbstractMap,实现 Map 接口 | 继承 AbstractMap,实现 NavigableMap、SortedMap 保证了 SortedMap 的有序性 |
实现方式 | 定义了 hashcode() 和 equals(),基于 hash 实现,可以根据初始容量和负载因子调优 | 红黑树总是处于平衡的状态,无法调优 |
遍历顺序 | 不能保证遍历顺序,因为 key 的 hash 值跟 hashcode 和表长度都有关系。 | 会按照排序后的顺序输出 |
长度限制 | 一个桶内链表达到 8 时转化为红黑树,表长最大为 Integer.Max | 红黑树没有长度限制 |
场景 | 通常情况下,HashMap 是要更快一点,毕竟数组嘛 | 需要排序才使用 TreeMap |