1. 容器分类
- Java 容器大致上分为 Collection 与 Map 两类,其中 Collection 主要用于存储对象的集合,而Map主要用于存储映射关系。
下面的代码会使用泛型,有兴趣的可以看下 java 泛型的简单理解 。
2. Collection
- Collection 主要是单个元素的集合,由List、Queue、Set三个接口区分不同的集合特征,实现对应的功能。
2.1 List
- List 可以存储重复的元素。面试常见的实现子类有 ArrayList、LinkedList、Vector(JDK1.5后基本不再用了)。
2.1.1 ArrayList
- 特点:按序存储,插入和删除慢,获取快。因为底层用的是数组,所以初始化长度适当的话,也可以减少运行时间。
import java.util.ArrayList;
public class ArrayListTest {
public static void main(String[] args) {
/* 初始化为 10000000,速度明显提升 */
ArrayList<Integer> arrayList = new ArrayList<>(100000);
long addStart = System.currentTimeMillis();
for(int i = 1; i <= 10000000; i++) {
arrayList.add(1);
}
long addEnd = System.currentTimeMillis();
System.out.println("ArrayList 添加数据的时间: " + (addEnd - addStart) + "毫秒");
long getStart = System.currentTimeMillis();
for(int i = 1; i <= 10000000; i++) {
arrayList.get(80000);
}
long getEnd = System.currentTimeMillis();
System.out.println("ArrayList 获取数据的时间: " + (getEnd - getStart) + "毫秒");
}
}
2.1.2 LinkedList
- 特点:不按序存储,插入删除快,查找慢,需要一个一个遍历
import java.util.LinkedList;
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<Integer> linkedList = new LinkedList<Integer>();
long addStart = System.currentTimeMillis();
for(int i = 1; i <= 100000; i++) {
linkedList.add(1);
}
long addEnd = System.currentTimeMillis();
System.out.println("linkedList 添加数据的时间: " + (addEnd - addStart) + "毫秒");
long getStart = System.currentTimeMillis();
for(int i = 1; i <= 100000; i++) {
linkedList.get(80000);
}
long getEnd = System.currentTimeMillis();
System.out.println("linkedList 获取数据的时间: " + (getEnd - getStart) + "毫秒");
}
}
2.1.3 Vector
- 跟 ArrayList 相似,但底层方法都加了锁,速度慢。
import java.util.Vector;
public class VectorTest {
public static void main(String[] args) {
Vector<Integer> vector = new Vector<>(100000);
long addStart = System.currentTimeMillis();
for(int i = 1; i <= 10000000; i++) {
vector.add(1);
}
long addEnd = System.currentTimeMillis();
System.out.println("vector 添加数据的时间: " + (addEnd - addStart) + "毫秒");
long getStart = System.currentTimeMillis();
for(int i = 1; i <= 10000000; i++) {
vector.get(80000);
}
long getEnd = System.currentTimeMillis();
System.out.println("vector 获取数据的时间: " + (getEnd - getStart) + "毫秒");
}
}
2.2 Queue
- 特点:讲究先进先出
import java.util.LinkedList;
import java.util.Queue;
public class QueueTest {
public static void main(String[] args) {
// add() 和 remove() 方法在失败的时候会抛出异常(不推荐)
Queue<Integer> queue = new LinkedList<>();
for(int i = 1; i <= 10; i++) {
queue.offer(i);
}
System.out.println("队列中的元素: " + queue);
while (queue.size() > 0) {
System.out.println("队列queue 的第一个元素出队: " + queue.poll());
}
}
}
2.3 Set
- 特点:不存储重复的元素,相同会覆盖。
public class SetTest {
public static void main(String[] args) {
HashSet<Integer> set = new HashSet<>();
for(int i = 1; i <= 100; i++) {
set.add(i & 15);
}
System.out.println("set 集合不存储重复元素:" + set);
}
}
3. Map
- Map 主要使用 (key,value) 键值对 存储映射关系。
3.1 HashMap
- 底层使用 数组 + 链表存储 节点, jdk1.8 新增红黑树,当链表长度的值 >=8 时转换为 数组 + 红黑树。因为使用了数组,查找会比较快。但是比较占空间。
import java.util.HashMap;
public class HashMapTest {
public static void main(String[] args) {
HashMap<Integer, String> hashMap = new HashMap<>();
long putStart = System.currentTimeMillis();
for(int i = 1; i <= 100000; i++) {
hashMap.put(i, "我的值是 --> " + i);
}
long putEnd= System.currentTimeMillis();
System.out.println("hashmap put值的时间: " + (putEnd - putStart));
long getStart = System.currentTimeMillis();
for(int i = 1; i <= 100000; i++) {
hashMap.get(i);
}
long getEnd= System.currentTimeMillis();
System.out.println("hashmap get值的时间: " + (getEnd - getStart));
HashMap<Integer, Integer> hashMap01 = new HashMap<>();
hashMap01.put("语文".hashCode(), 100);
hashMap01.put("书序".hashCode(), 100);
hashMap01.put("速度快你".hashCode(), 100);
hashMap01.put("数学".hashCode(), 100);
hashMap01.put("的难上加难".hashCode(), 100);
hashMap01.put("是可能".hashCode(), 100);
hashMap01.put("电脑看".hashCode(), 100);
hashMap01.put("低年级".hashCode(), 100);
hashMap01.put("到你家".hashCode(), 100);
hashMap01.put("电多米尼克".hashCode(), 100);
hashMap01.put("电脑卡".hashCode(), 100);
hashMap01.put("你电脑".hashCode(), 100);
System.out.println(hashMap01);
}
}
3.2 TreeMap
- 特点:使用 tree 结构保存节点,查询慢,但占空间小,适用于按序(key)存储的结构。
import java.util.HashMap;
import java.util.TreeMap;
public class TreeMapTest {
public static void main(String[] args) {
TreeMap<Integer, String> treeMap = new TreeMap<>();
long putStart = System.currentTimeMillis();
for(int i = 1; i <= 1000000; i++) {
treeMap.put(i, "我的值是 --> " + i);
}
long putEnd= System.currentTimeMillis();
System.out.println("treeMap put值的时间: " + (putEnd - putStart));
long getStart = System.currentTimeMillis();
for(int i = 1; i <= 1000000; i++) {
treeMap.get(i);
}
long getEnd= System.currentTimeMillis();
System.out.println("treeMap get值的时间: " + (getEnd - getStart));
TreeMap<Integer, Integer> treeMap01 = new TreeMap<>();
treeMap01.put("语文".hashCode(), 100);
treeMap01.put("书序".hashCode(), 100);
treeMap01.put("速度快你".hashCode(), 100);
treeMap01.put("数学".hashCode(), 100);
treeMap01.put("的难上加难".hashCode(), 100);
treeMap01.put("是可能".hashCode(), 100);
treeMap01.put("电脑看".hashCode(), 100);
treeMap01.put("低年级".hashCode(), 100);
treeMap01.put("到你家".hashCode(), 100);
treeMap01.put("电多米尼克".hashCode(), 100);
treeMap01.put("电脑卡".hashCode(), 100);
treeMap01.put("你电脑".hashCode(), 100);
System.out.println(treeMap01);
}
}
4 小总结
- 以上是对常见容器的一点概述与验证,接下来的系列会逐个讲解其核心原理及源码。