目录
- 1、集合框架的由来
- 2、集合框架的结构(jdk1.8)
- 2.1、Collection框架结构
- 2.2、Map框架结构
- 3、集合的遍历
- 3.1、for循环原理
- 3.2、Iterator循环原理
- 3.3、foreach循环原理
- 3.4、demo演示
- 4、面试相关
1、集合框架的由来
在编程设计中,数据结构(算法)担任着不可或缺的角色,在JAVA语言中,JAVA的设计者将数据结构进行了封装,这个封装的整体就叫做集合框架,在进行JAVA应用程序开发时,可以根据需要创建相应的对象,而不必再去设计数据结构和具体的算法实现,这样就大大提高了编程效率。
2、集合框架的结构(jdk1.8)
JAVA集合框架主要由两个接口派生而出,分别是Collection接口进入Map接口,这是集合框架的两个根接口,其中Collection接口的实现类直接保存对象,而Map接口的实现类是用键值对(key-value)的形式保存数据的,可以根据key值获取相应的value值。下面来看他们具体的结构吧。
2.1、Collection框架结构
上图展示了Collection体系里的集合,其中紫色的代表的是接口,淡蓝色的代表的是具体的实现类。根据上图可以知道,Collection接口下面有三个子接口,分别是List、Queue、Set。三个子接口下面就是他们具体的一些实现类了。实际中国常用的类有ArrayList、HashSet、TreeSet等等。至于这些类的源码分析后期会具体分析。
现在先来看一下List接口和Set接口的区别:
再来看一下三个接口下面常用的ArrayList、LinkedList、HashSet三个子类的一些简单的区别吧。
那么最后一个问题,上述集合实现类中有哪些是线程安全的呢?
- 在上述Collection接口结构图中,线程安全的只有Vector和Stack,其余的都是线程不安全的。
- 线程安全的List有Collections.synchronizedList;
- 在jdk的java.util.concurrent包下的所有集合类都是线程安全的。比如CopyOnWriteArrayList、CopyOnWriteArraySet、SynchronousQueue等。
2.2、Map框架结构
Map接口的实现类是用键值对(key-value)的形式保存数据的,可以根据key值获取相应的value值,值得注意的是Map接口的所有实现类中的key是不可重复的。下面来看看Map接口的具体结构吧。
如上图所示,Map接口下面有很多的实现类,下面简单的介绍一下主要的几个实现类的底层数据结构、是否线程安全等一些特点:
除了上面已知的HashTable是线程安全的,你还知道那些线程安全的Map类呢?
- 应该很容易猜到了,jdk下面的java.util.concurrent包下的所有Map类都是线程安全的,比如经常说ConcurrentHashMap。juc包是jdk的线程并发包。有兴趣的同学可以去研究一下。
3、集合的遍历
集合的遍历有两种方式:分别是for循环和、foreach循环和Iterator接口遍历。下面分析一下它们三个遍历速度的快慢及其底层原理。
3.1、for循环原理
for循环遍历是基于元素的位置,按位置进行读取,通俗的来讲就是对元素的下标进行直接访问,因此对于顺序存储的数据结构(例如数组),对特定位置的元素查询的平均时间复杂度是O(1)。而对非顺序存储的数据结构(如链表),那么读取特定位置元素的平均时间复杂度是O(n)。
3.2、Iterator循环原理
Iterator接口是所有集合框架的父接口,它每次遍历集合的时候都需要保存当前遍历的位置,然后根据当前位置来向前或者向后移动指针,直至循环完当前所有的元素。因此对于任何集合来说,它的平均时间复杂度为O(n)。
3.3、foreach循环原理
通过Java字节码可以知道,foreach内部实现也是通过Iterator实现的,只时这个Iterator是由Java编译器生成的,因此时间复杂度和Iterator一样。但是因为foreach每次都要做类型转换检查,所以花费的时间比Iterator略长。
总结: for循环、foreach循环和Iterator循环的遍历速度需要根据具体集合的数据结构进行判定,
- 对于顺序存储的集合如ArrayList,那么此时的遍历速度:for > Iterator > foreach。
- 对于非顺序存储的集合如LinkedList,那么此时的遍历速度:Iterator > foreach > for
3.4、demo演示
用for循环和foreach循环遍历List集合, 用Iterator遍历
public class ArrayListTest {
public static void main(String[] args) {
//定义List
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
//for循环遍历
for (int index = 0; index < list.size(); index++) {
System.out.println(list.get(index));
}
//foreach循环遍历
list.forEach(s -> System.out.println(s));
//定义HashMap
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("key1", "value1");
hashMap.put("key2", "value2");
//遍历hashMap
Iterator it = hashMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
System.out.println("打印Key值" + entry.getKey());
System.out.println("打印Vaule值" + entry.getValue());
}
}
}
4、面试相关
- 说一下你对集合类的认识?
JAVA的集合类是对数据结构的封装,集合类存储的数据类型是引用数据类型,集合框架的有两个根接口:Collection接口和Map接口,其中Collection接口有List接口、Set接口、Queue接口。Map接口的实现类有HashMap、TreeMap、HashTable等。 - List和Set有什么区别?
- 你知道哪些线程安全的集合类?
Collection下面有Vector和Stack,Map下面有HashTable,EnumTable。另外jdk下面的java.util.concurrent包下的所有集合类都是线程安全的。 - List集合和数组有什么区别?
1>集合大小不固定;但是数组长度是固定的,一旦创建无法改变;
2>集合可以存放多种类型(不加泛型时添加的类型是Object);而数组的存放的类型只能是一种,
3>ArrayList是基于数组创建的容器类