一、常用的集合类简介
Java 容器分为 Collection 和 Map 两大类,Map接口和Collection接口是所有集合框架的父接口:
Collection接口的三种子接口包括:Set接口、List接口和Queue接口;
方法名 | 作用 |
---|---|
add(Object obj):boolean | 添加,存储的是对象的引用 |
size():int | 容器中元素的实际个数 |
remove(Object obj) :boolean 以及 clear() | 删除 |
contains(Object obj) :boolean 以及 isEmpty() :boolean | 判断元素 |
iterator():iterator | 遍历元素 |
1.Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等;
-
HashSet
底层实现:Hashtable哈希表存储结构
适用场景:
• 优点:添加速度快,查询速度快,删除速度快
• 缺点:无序 -
TreeSet
时间复杂度:
底层实现:采用二叉树(红黑树)的存储结构,TreeMap来实现,
适用场景:
• 优点:有序(排序后的升序)查询速度比List快
• 缺点:查询速度没有HashSet快 -
LinkedHashSet
底层实现:采用哈希表存储结构,同时使用链表维护次序;有序(添加顺序)
适用场景:
常用方法:
2.List(线性表)接口的实现类主要有:ArrayList、LinkedList、Stack、Vector
List接口常用的方法:
• E get(int index); //获取元素
• subList(from,to); //获取元素
• listIterator(); //获取元素
• E set(int index, E element); //使用element替换指定索引位置上的元素
• void add(int index, E element); //在指定索引的位置上插入元素
• addAll(index,Collection) //在指定的引的位置上插入整个集合的元素
• addAll(Collection) //在结束插入整个集合的元素
• E remove(int index); //根据索引删除指定的元素
• int indexOf(Object o);
-
ArrayList
底层实现:动态数组
适用场景:
• 优点:遍历元素和随机访问元素的效率比较高;
• 缺点:添加和删除需要大量移动元素效率低,按照内容查询效率低;
常用方法: -
LinkedList
时间复杂度:O(n)
底层实现:链表存储方式,双端队列
适用场景:
• 优点:插入、删除元素时效率比较高
• 缺点:遍历和随机访问元素效率低下
常用方法:常用方法: 可抛出异类的 返回元素的 Insert(插入) add(e) offer(e) Remove(移除) remove() poll() Examine(检查) element() peek()
LinkedList特有的方法:
序号 方法名 作用 1(增) addFirst(Object obj); 添加头 addLast(Object obj); 添加尾 offerFirst(Object obj); 1.6版本之后的加头 offerLast(Object obj); 1.6版本之后的加尾巴 2(删) removeFirst(); 删除头 获取元素并删除元素 removeLast(); 删除尾 pollFirst(); 1.6版本之后的删头 pollLast(); 1.6版本之后的删尾 3(查) getFirst(); 获取头 获取元素但不删除 getLast(); 获取尾 peekFirst(); 1.6版本之后的获取头 peekLast(); 1.6版本之后的获取尾
-
Stack-----Vector的子类
时间复杂度:
底层实现:
适用场景:
常用方法:public Object push(Object item): 将指定对象压入栈中。 Public Object pop(): 将栈最上面的元素从栈中取出,并返回这个对象。 public boolean empty(): 判断栈中没有对象元素。
-
Vector
时间复杂度:
底层实现:动态数组,所有方法默认都加synchronized
适用场景:
常用方法:
3.Queue(队列)接口(专门为高并发,多线程使用),注重要的实现类
**Map接口的实现类主要有:Hashtable、HashMap、synchronizedHashMap(加带锁版本)、 ConcurrentHashMap(多线程基本用它)以及Properties等
序号 方法 作用
1(添加) put(key,value) 添加元素
2(删除) clear() 清除所有
remove(key) 根据key去移除
3(判断) containsKey(key) 是否包含指定的key
containsValue(value) 是否包含指定的值
isEmpty() 判断集合中元素是否为空
4(遍历) get(key)
size()
values()
entrySet()
keySet()
- HashMap (哈希表)
Key无序 唯一(Set),Value无序不唯一(Collection)
底层实现:基于哈希表,完全没有加锁,线程不安全
常用方法:
map.put(1000000, "我是1000001"); //添加(key,value),如果存在则是更新value
map.containsKey(1); //查key是否存在,返回Boolean类型
map.get(10); //获取当前key的value
map.remove(4); //删除
- TreeMap(有序表)
底层实现: 红黑树
适用场景: 有序,速度没有hash快;所有方法默认都加synchronized
常用方法:
treeMap.put(2, "我是2");
treeMap.containsKey(1);
treeMap.get(10);
比哈希表多的功能:
treeMap.firstKey();
treeMap.lastKey();
// <= 4
treeMap.floorKey(4); //小于等于4,离4最近的
// >= 4
treeMap.ceilingKey(4); //大于等于4,离4最近的
// O(logN)
注:不如哈希表的地方是:上面提到的所有的接口的时间复杂度认为O(logN)
二、List,Set,Map,Queue四者的区别?
1.List:一个有序(元素存入集合的顺序和取出的顺序一致)容器;
- 元素可以重 复,可插入多个null元素,元素都有索引;
- Lis容器中的元素都对应一个整数型的序号记载其在容器中的位置,可根据序号存取容器中的元素
- List支持for循环(基于计数器)、也可迭代器(iterator)、还可foreach (内部采用iterator方式实现,只能简单遍历)循环遍历;
2.Set:一个无序、(存入和取出顺序有可能不一致)容器;
- 不可以存储重复元素, 只允许存入一个null元素,必须保证元素唯一性。
- set只能用迭代
- 操作数据的方法与List类似,Set接口不存在get()方法
3.Map是一个键值对集合,存储键、值和之间的映射。 键值不能重复
- Key无序,唯一;value 不要求有序,允许重复。
- Map没有继承于Collection接口,从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。
问1:Set和List对比:
- Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
- List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变
问2:Set不Map有关系吗?
- 采用了相同的数据结构,只用于map的key存储数据,以上是Set
问3:Queue与List的区别:
- 主要就是:Queue添加了许多对线程友好的API
offer、peek、poll,他的一个子类型叫BlockingQueue对线程友好的API又添加put和take,这两个实现阻塞操作。
5.如何实现数组和List之间的转换?
- List 转数组:使用 List 自带的 toArray() 方法。
// list to array
List<String> list = new ArrayList<String>();
list.add("123");
list.add("456");
list.toArray();
- 数组转 List:使用 Arrays. asList(array) 进行转换。
// array to list
String[] array = new String[]{"123","456"};
Arrays.asList(array);
三、迭代器Iterator
所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现了Iterator接口的对象。
1.Iterator 的特点是只能单向遍历,但是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException 异常。
2.使用方法:
List<String> list = new ArrayList<>();
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String obj = it.next();
System.out.println(obj);
3.Iterator接口定义的方法:
boolean hasNext(); //判断是否有元素没有被遍历
Object next(); //返回游标当前位置的元素并将游标移动到下一个位置
void remove(); //删除游标左面的元素,在执行完next之后该操作只能执行一次
3.Iterator.remove() 方法进行边遍历边移除Collection中的元素,是在迭代过程中删除元素的唯一的安全方法,示例如下:
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
*// do something*
it.remove(); }
- 注:当使用 foreach( for( Integer i : list ) ) 语句时,会自动生成一个iterator 来遍历该list,但同时该 list 正在被 Iterator.remove() 修改。Java 一般不允许一个线程在遍历 Collection时另一个线程修改它,会产生ConcurrentModificationException 异常。
4.Iterator 和 ListIterator的区别:
- Iterator 可以遍历 Set 和 List 集合,而 ListIterator 只能遍历 List。
- Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前/后遍历)。
- ListIterator 实现 Iterator 接口,然后添加一些额外的功能(添加一个元 素、替换一个元素、获取前面或后面元素的索引位置)
四、如何选择数据结构
衡量标准:读的效率和改的效率
- Array读快改慢
- Linked改快读慢
- Hash两者之间
五、总结