一、为什么需要集合?
首先,我们要知道为什么需要集合这种容器类型。我们已经有了数组,但数组存在以下局限性:
(1)数组大小固定,一旦创建,大小就无法改变
(2)数组只能存储相同的数据类型
(3)数组只能按照索引位置(数组下标)进行存取
所以,我们引入了集合。
二、集合的分类
集合主要分为两类:Collection和Map
collection接口在java中主要有三类实现:List、Set、Queue
(1)List的特点是元素有序且可重复
(2)Set的特点是元素无序且不可重复
(3)Queue表示的是队列
Map也是一个集合接口,它主要提供键值对对象的存取,主要实现有:HashMap、Hashtable、LinkedHashMap、ConcurrentHashMap
三、集合的使用场景概述
什么场景下使用list,set,map呢?
- 如果你经常会使用索引来对容器中的元素进行访问,那么List是你的正确的选择。如果你已经知道索引了的话,那么List的实现类比如ArrayList可以提供更快速的访问,如果经常添加删除元素的,那么肯定要选择LinkedList。
- 如果你想容器中的元素能够按照它们插入的次序进行有序存储,那么还是List,因为List是一个有序容器,它按照插入顺序进行存储。
- 如果你想保证插入元素的唯一性,也就是你不想有重复值的出现,那么可以选择一个Set的实现类,比如 HashSet、LinkedHashSet或者TreeSet。所有Set的实现类都遵循了统一约束比如唯一性,而且还提供了额外的特性:比如TreeSet还是一个SortedSet,所有存储于TreeSet中的元素可以使用Java里的Comparator或者Comparable进行排序。LinkedHashSet也按照元素的插入顺序对它们进行存储。
- 如果你以键和值的形式进行数据存储那么 Map 是你正确的选择。你可以根据你的后续需要从 Hashtable、HashMap、TreeMap 中进行选择。
四、集合细分的区别及适用场景
1、基本区别:
(1)List的特点是元素有序且可重复,可动态增长,查找元素效率高,插入删除元素效率低,插入和删除会引起其他元素位置改变。
(2)Set的特点是元素无序且不可重复,重复元素会覆盖掉,只允许一个null元素,查找元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
(3)Map适合存储键值对数据,Map的每个Entry都持有两个对象,也就是一个键一个值。Map可能会持有相同的值对象,但键对象必须是唯一的,可以拥有随意个null值但最多只能有一个null键。
2、线程安全:
-
LinkedList、ArrayList是非线程安全的,Vector是线程安全的
-
HashMap、HashSet是非线程安全的,HashTable是线程安全的
-
StringBuilder是非线程安全的,StringBuffer是线程安全的
3、ArrayList与LinkedList的区别和适用场景
Arraylist:
优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。
缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。
LinkedList:
优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景
缺点:因为LinkedList要移动指针,所以查询操作性能比较低。
适用场景分析:
当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。
4、ArrayList与Vector的区别和适用场景
ArrayList和Vector都是用数组实现的,主要有这么三个区别:
(1)Vector类中的方法很多有synchronized进行修饰,所以线程安全,但效率低,一般不赞成使用。
(2)两个都是采用的线性连续空间存储元素,但是当空间不足的时候,两个类的增加方式是不同。
(3)Vector可以设置增长因子,而ArrayList不可以。
适用场景分析:
1)、Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。
2)、如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。
5、HashSet与Treeset的适用场景
两者中的值都不能重复
(1)TreeSet 是二叉查找树实现的,数据自动排好序,不允许放入null值
(2)HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null。
(3)HashSet要求放入的对象必须实现hashCode()方法,放入的对象,是以hashCode码作为标识的,而具有相同内容的String对象,hashCode是一样,所以放入的内容不能重复,但是同一个类的对象可以放入不同的实例
适用场景分析:
HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。为快速查找而设计的Set,我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。
6、HashMap、TreeMap、Hashtable的区别及适用场景
HashMap非线程安全,不支持重复键,基于哈希表实现,无序,允许存储一个null键和多个null值。
TreeMap非线程安全,不支持重复键,基于红黑树实现,有序,不允许存储null键,但可能包含多个null值。
Hashtable线程安全,不允许存储null键和null值。
适用场景分析:
1)、HashMap和Hashtable区别
Hashtable是同步的,而HashMap是非同步的,效率上比Hashtable要高。
HashMap允许空键值,而Hashtable不允许。
2)、HashMap和TreeMap区别
HashMap:适用于Map中插入、删除和定位元素。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
五、集合的遍历
1、List集合遍历
(1)普通for循环:
List<String> list = new ArrayList<String>();
list.add("北京");
list.add("上海");
list.add("广州");
list.add("西安");
//通过普通for循环,相当于根据数组的小标遍历集合
for(int i = 0;i<list.size();i++) {
System.out.print(list.get(i)+" ");
}
(2)增强for(底层使用迭代器):
for (String s : list) {
System.out.print(s+" ");
}
(3)Iterator迭代器:
Iterator it = list.iterator();//获取迭代器对象
while(it.hasNext()) {//判断集合是否有下一个元素,也就是判断有没有到集合尾部
System.out.print(it.next()+" ");//获取集合中的元素并输出
}
2、set集合遍历
(1)增强for(简单的for循环不适用set)
Set<String> set = new HashSet<String>();
set.add("Monday");
set.add("Sunday");
for (String s : set) {
System.out.print(s+" ");
}
(2)Iterator迭代器:
Iterator it = set.iterator();
while(it.hasNext()) {
System.out.print(it.next()+" ");
}
3、map集合遍历
(1)获取Map的keySet():通过遍历key,获取对应的value,从而遍历键值对:
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("令狐冲", 30);
map.put("东方不败", 28);
map.put("上官子怡", 21);
for (String key : map.keySet()) {//遍历Map集合的keySet集合
Integer value = map.get(key);//获取 value
System.out.println(key + "--" + value);
}
(2)获取Map集合的Entryset(),遍历Map的Entry集合,直接获取键值对对象
for(Entry<String, Integer> entry:map.entrySet()) {
System.out.println(entry);
}
(3)Iterator迭代器:
Iterator<Entry<String, Integer>> it = map.entrySet().iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
参考链接