哪怕再没有时间,记一道题也是一个小小的进步。
1、什么是集合?
- 集合就是一个放数据的容器,准确的说是存放数据对象的容器。
- 集合类存放的都是对象的引用,而不是对象的本身。
- 集合类型主要有三种:Set(集)、List(列表)、Map(映射)
2、常用的集合类有哪些?
- Map接口和Collection接口是所有集合框架的父接口。
- Collection接口的子接口包括:Set接口和List接口。
- Map接口的实现类主要有:HashMap、TreeMap、HashTable、ConcurrentHashMap以及Properties等。
- Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等。
- List接口的实现类主要有:ArrayList、LinkedList、Stack、Vector等。
3、List,Set,Map三者的区别?
- Collection:单列集合
- List:有序、可重复
- Vector:数组结构、线程安全
- ArrayList:数组结构、非线程安全
- LinkedList:链表结构、非线程安全
- Set:无序、唯一
- HashSet:哈希表结构
- LinkedHashSet:哈希表结构+链表结构
- TreeSet:红黑树结构
- Map:双列集合(key唯一)
- HashTable:哈希表结构,线程安全
- 数组 + 链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的,
- HashMap:哈希表结构,非线程安全
- JDK1.8 之前 HashMap 由数组 + 链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法” 解决冲突) 。
- .JDK1.8
以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8
)时,将链表转化为红黑树,以减少搜索时间。
- TreeMap:红黑树
- LinkedHashMap:
- LinkedHashMap 继承自 HashMap ,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。
- LinkedHashMap
在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
4、哪些集合类是线程安全的?
Vetory:比ArrayList多了一个synchronized(线程安全),因为效率比较低,现在不建议使用。
HashTable:比HashMap多了个synchronized(线程安全),不建议使用。
ConcurrentHashMap:是Java5中支持高并发、高吞吐量的线程安全HashMap实现。它由Segment数组结构和HashEntry数组结构组成。(推荐使用)
5、迭代器是什么?
Iterator 接口提供遍历任何 Collection 的接口。
所有Collection接口都继承了Iterator迭代器。
Iterator使用代码如下:
List<String> list = new ArrayList<>();
Iterator<String> it = list.iterator();
while(it.hasNext()){
String obj = it.next();
System.out.println(obj);
}
Iterator 的特点是只能单向遍历,但是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModifificationException 异常。
6、 如何边遍历边移除 Collection 中的元素?
List<String> list = new ArrayList<>();
Iterator<String> it = list.iterator();
while(it.hasNext()){
String obj = it.next();
System.out.println(obj);
//加remove即可
it.remove();
}
有一种常见的错误写法:
ConcurrentModifificationException 异常,因为使用for循环的时候,内部会生成一个Iterator来遍历list获取对象,相当于有两个线程再执行这个list。Java 一般不允许一个线程在遍历 Collection 时另一个线程修改它。所以会抛出异常。
7、Iterator 和 ListIterator 有什么区别?
Iterator 可以遍历 Set 和 List 集合,而 ListIterator 只能遍历 List 。
Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前 / 后遍历)。
ListIterator 实现 Iterator 接口,然后添加了一些额外的功能,比如添加一个元素、替换一个元
素、获取前面或后面元素的索引位置。
8、遍历一个List有几种方式?每一种的实现原理是什么?Java中最佳的遍历是什么?
遍历方式有以下三种:
- for 循环遍历,基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素, 当读取到最后一个元素后停止。
- 迭代器遍历,Iterator
。
Iterator
是面向对象的一个设计模式,目的是屏蔽不同数据集合的特
点,统一遍历集合的接口。 Java 在 Collections 中支持了 Iterator 模式。 - foreach 循环遍历。foreach 内部也是采用了 Iterator 的方式实现,使用时不需要显式声明 Iterator 或计数器。优点是代码简洁,不易出错;缺点是只能做简单的遍历,不能在遍历过 程中操作数据集合,例如删除、替换。
最佳的遍历是什么?
Collections框架中提供了一个叫Random Access,用来标记List实现是否支持Random Access。
如果实现了Random Access可以使用for循环遍历,否则就使用Iterator或者foreach遍历。
9、说一下ArrayList的优缺点
优点:底层使用数组实现,是一种随机访问模式,由于他实现了Random Access,所以他查询的时候非常快,按顺序添加元素也非常方便。
缺点:删除元素需要使用元素复制操作,如果元素多时,非常消耗性能。不按顺序,即某个位置插入元素时,也需要进行元素复制,元素多时,也是非常消耗性能。
所以ArrayList适合按顺序添加元素以及随机访问场景。
10、多线程场景下如何使用 ArrayList?
ArrayList 不是线程安全的,如果遇到多线程场景,可以通过 Collections 的 synchronizedList 方法将其转换成线程安全的容器后再使用。
List<String> synchronizedList = Collections.synchronizedList(list); synchronizedList.add("aaa");
synchronizedList.add("bbb");
for (int i = 0; i < synchronizedList.size(); i++) {
System.out.println(synchronizedList.get(i));
}