最近在准备大三暑假的实习面试,所以重温了一下Java基础,当初大二自学Java,到现在回头重新学习,感觉到了enjoy Java开发的乐趣。废话
不多说,现在就Java的集合框架做一些总结。
Java集合的出现是为了解决数组的长度有限问题的,先说说Java集合和数组的区别:
1、数组长度固定,集合长度不固定。
2、数组可以存储基本类型,也可以存储引用类型,而集合只能存储引用类型。
Java集合分为两大类,可以理解为实现了Collection接口的单列数据集合和实现了Map集合的双列数据(key--value)集合。那就首先来说说实现
Collection接口的集合。
1、Collection集合体系
1、1 Collection 集合继承体系结构图:
1、2 List集合:
List接口继承自Collection接口,实现List接口的集合是有序的(这里的有序指的是存储顺序与读出顺序一致)。且元素是可重复的,元素值允许为null。
ArrayList:
ArrayList集合底层数据结构是数组,因此它查询快,增删慢。且ArrayList是线程不安全的,因此性能较高。(鉴于元素的可重复性,我们可以看看
JDK中ArrayList的Boolean add(Object o)方法源码,该方法无论传入一个什么值,都是返回true,因此什么元素都能添加成功,以至于可重复。)
LinkedList:
LinkedList集合底层的数据结构是双向链表,所以它查询慢,增删快,且可以被当做队列和栈结构来使用;LinkedList是线程不安全的,因此性能较高。
Vector:
Vector集合底层数据结构是数组,和ArrayList集合一样,查询快,增删慢,但是它是线程安全的,因此性能相对来说比较低,Vector是一个比较古老的集合,
现在开发基本不使用它。但有人就纳闷了,如果想使用线程安全的List难道不是使用Vector么?对于这个问题,Java提供Collections工具类的某些方法将一些线程不安全 的集合封装为线程安全的集合,这个具体在后面会说到。
1、3 Set集合
Set集合是无序的且元素是不允许重复的,对于Set集合元素的不可重复性,我们可以查看JDK中HashSet的源码,HashSet的构造方法源码如下图:
原来我们创建一个HashSet对象时,底层实际上是创建了一个HashMap对象(对于HashMap,后面会有详细介绍),我们知道,HashMap集合的Key是不可重复的,值是可重复 的,所以HashSet的元素实际上就是一个HashMap集合的key,这个HashMap的值都为null。至于如何保证Set集合元素的不可重复性,主要是依赖于hashCode()和 equals()方法来保证的,判断一个元素是否重复的步骤是:先通过hashCode()方法比较两个元素的hashCode值是否相等,若不相等,则不是重复元素,若相等,则再判 断两个元素通过equals()方法的返回值,若为false。则不是重复元素,若为true,则是同一个元素,不进行插入。
HashSet:
HashSet底层数据结构是哈希表,通过元素的hashCode来决定存储位置,是线程不安全的,元素值允许为null。另外,若往HashSet中添加重复的元素,运行不会抛出任何异常,只是添加时调用的Boolean add(Object o)方法返回false。
LinkedHashSet:
LinkedHashSet是HashSet集合的子类,它的底层数据结构是链表和哈希表,链表用于维护元素的插入顺序,也就是说,LinkedHashSet元素是有序的,但是其集合元素仍不可重复,且LinkedHashSet是线程不安全的。
TreeSet:
TreeSet集合底层数据结构是红黑树(一种自平衡的二叉树),红黑树的作用是确保插入的元素处于排序状态,这个排序的规则分为自然排序和使用比较器的定制排序。自然排序,即元素具备比较性,让元素实现Comparable接口即可。比较器定制排序,即集合具备比较性,让集合的构造方法接收一个Comparator实现类对象即可,在Comparator实现类对象里面我们通过实现compare()方法来定制我们的排序规则,制定排序规则的时候注意正确区分主要条件与次要条件。此外,TreeSet集合是线程不安全的。
1、4关于Collection集合的几个问题:
编程时如何选择Collection?
看需求,要求有序吗?
true:选择List。若要求查询多,修改少,选择ArrayList,若要求修改多,查询少,选择LinkedList。若不确定,就是用ArrayList。
false:选择Set。若要求插入取出顺序一致,选择LinkedHashSet,否则选择HashSet,若要求排序,选择TreeSet。
要求安全吗?
true:不推荐使用Vector,可以使用Collections工具类提供的synchronizedXxx()方法将上述的集合封装为线程安全的集合,且最好在创建集合时就开始封装。
false:参考上述的是否有序要求。
集合的线程安全问题:
Collection集合里的HashSet,LinkedHashSet,TreeSet,ArrayList,LinkedList都是线程不安全的,Vector是线程安全的,但是如果我们需要使用线程安全的的集 合,可以使用Collections工具类提供的synchronizedXxx()方法将上述不安全的集合封装为线程安全的集合。比如:创建一个线程安全的ArrayList集合:
List safetyList = Collections.synchronizedList(new ArrayList());
2、Map集合体系
2、1 (常用)Map集合继承体系结构图
Map集合是基于key--value映射关系的一种数据结构,key不允许重复,value允许重复,所以他们具有单向的一对一关系。
HashMap:
HashMap集合底层数据结构是哈希表,且HashMap是线程不安全的,其key和value均可以允许为null(但是要遵循key唯一的原则喔),HashMap底层采用数组来存储key--value对,且HashMap的Iterator迭代器采用的是快速失败机。
Hashtable:
请注意,Hashtable不要写成HashTable!Hashtable的命名规格不符合Java规范,这是历史遗留原因,不需理会。Hashtable底层数据结构也是使用的哈希表,但他是线程安全的,且key和value均不允许为null,否则会抛出NullPointerException异常。其enumerator迭代器没有采用快速失败机制。
LinkedHashMap:
根据上面LinkedHashSet和HashSet的联系,我们可以推出LinkedHashMap底层数据结构是链表和哈希表,链表用于维护元素的插入顺序,以达到元素的有序性,它是线程不安全的。
2、2 HashMap和Hashtable的区别
答案就在上面。
最后,对于Collection集合和Map集合的基本API,在这里就不总结了,读者可以自行查看API文档。