Java面试篇之容器篇
Collection
存放独立元素的序列。Collection下又有三个子接口,List,Set,Queue。
List
一个有序的Collection(也称序列),元素可以重复。确切的讲,列表通常允许满足 e1.equals(e2) 的元素对 e1 和 e2,并且如果列表本身允许 null 元素的话,通常它们允许多个 null 元素。实现List的有:ArrayList、LinkedList、Vector、Stack等。
Set
一个不包括重复元素(包括可变对象)的Collection,是一种无序的集合。Set不包含满 a.equals(b) 的元素对a和b,并且最多有一个null。实现Set的接口有:EnumSet、HashSet、TreeSet等。
Queue
一种队列则是双端队列,支持在头、尾两端插入和移除元素,主要包括:ArrayDeque、LinkedBlockingDeque、LinkedList。另一种是阻塞式队列,队列满了以后再插入元素则会抛出异常,主要包括ArrayBlockQueue、PriorityBlockingQueue、LinkedBlockingQueue。
Map
存放key-value型的元素对。
1.常见容器:
String,数组以及java.util下面的集合类
List:存放有序,列表存储,元素可重复 ArrayList LinkedList Vector
Set:无序,元素不可重复 HashSet TreeSet
Map:无序,元素可重复 HashMap TreeMap LinkedHashMap HashTable
2.Collection 和 Collections 有什么区别?
Collection是集合类的一个顶级接口,它提供了对集合对象进行基本操作的通用接口方法.
Collections是集合类的一个工具类,它提供了一系列的静态方法,用于对集合中元素进行排序,搜索以及线程同步等操作.
3.List、Set、Map 之间的区别是什么?
- List: 可以允许重复的对象;
可以插入多个null元素;
有序,输入顺序就是输出顺序; - Set: 不允许重复对象;
无序,且只允许一个null对象; - Map: 存储键值对,只能有唯一的key,value可以重复
只能有一个null键
4.HashMap 和 Hashtable 有什么区别?
一. HashMap可以接受null键和值,HashTable不行
二. HashTable是线程安全的,通过synchronized来保证,而HashMap线程不安全
三. HashMap的迭代器是fail-fast迭代器,而HashTable的enumerator迭代器不是fail-fast.
5.如何决定使用 HashMap 还是 TreeMap?
HashMap基于散列表实现,适用于查询频繁的情况
TreeMap基于红黑树实现,适用于创建比较多的情况.且TreeMap存储数据是按照字母表的顺序存储的,如果对顺序有要求也可以选用TreeMap.
6.说一下 HashMap 的实现原理?(重点!!!)
数组+链表,初始16,0.75扩容,数据存在内部类Map.Entry中,其中包含key value hashcode和next.
详细👇
- HashMap 基于 Hash 算法实现的,我们通过 put(key,value)存储,get(key)来获取。
- 当传入 key 时,HashMap 会根据 key. hashCode() 计算出 hash 值,根据 hash 值将 value 保存在 bucket 里。
- 当计算出的 hash 值相同时,我们称之为 hash 冲突,HashMap 的做法是用链表和红黑树存储相同 hash 值的 value。
- 当 hash 冲突的个数比较少时,使用链表否则使用红黑树。
- HashMap 对应的线程安全类是 ConcurrentHashMap
7. HashMap的工作原理
- HashMap是面向查询优化的数据结构,查询性能优异。
- 在其内部利用数组存储数据。
- 插入数据时,先根据Key的HashCode计算出数组的下标位置,再利用Key的equals()方法检查是否以存在重复的Key,如果不重复直接存储到数组中,如果重复就作为链表存储到散列桶中。
- 插入的数据和数组容量的比值大于加载因子则进行数组扩容,并重新散列,默认的加载因子为“0.75”。
- 查询时,先根据Key的HashCode计算出数组的下标位置,再利用Key的equals()方法检查到Key的位置,如果找到返回Key对应的Value,否则返回Null。
- 由于利用Key的HashCode直接计算出数据的存储位置,由于直接确定数据的存储位置,相对于其他查找方式,查询效率非常高。
8.说一下 HashSet 的实现原理?
HashSet基于HashMap实现,默认构造函数是构造一个初始容量为16的HashMap,所有放入HashSet
集合的元素实际上由HashMap的key来保存,而value则保存了一个PRESENT的静态Object对象,因为元素都保存在key中,所以才能不重复.
9.ArrayList和LinkList的区别?
- ArrayList(底层基于动态数组):
优点:get和set调用花费常数时间,也就是查询的速度快
缺点:新项的插入和现有项的删除代价昂贵,也就是添加删除的速度慢 - LinkedList(基于链表实现,底层是循环双向链表):
优点:新项的插入和和现有项的删除开销很小,即添加和删除的速度快
缺点:对get和set的调用花费昂贵,不适合做查询
另一种说法👇
-
ArrayList底层基于动态数组,LinkedList基于链表实现,底层是循环双向链表
-
对于随机访问get和set,ArrayList优于LinkedList.
-
对于新增add和删除remove,LinkedList比较快
10.ArrayList的扩容机制
jdk7,底层创建了长度是10的Object[]数组,如果添加导致数组容量不够,则扩容,扩容为原来的1.5倍,同时将原数组中的数据复制到新的数组中。
jdk8,刚开始调用构造方法时并没有创造长度为10的Object[]数组,而是第一次调用add()时,底层才创建了长度为10的数组
11.ArrayList 和 Vector 的区别
ArrayList是List接口的主要实现类,底层使用Object数组存储,适用于频繁的查找工作,线程不安全。Vector是List的古老实现类,底层使用Object数组存储,线程安全的。
jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组,在扩容方面,默认扩容为原来数组长度的2倍。
12.如何实现数组和 List 之间的转换?
List转成为数组,调用ArrayList.toArray()方法,数组转化为list,调用Arrays.asList()方法。
13. 哪些集合类是线程安全的?
Vector HashTable ConcurrentHashMap Stack
14.在 Queue 中 poll()和 remove()有什么区别?
Queue中,add方法和offer方法都可以添加元素,而remove和poll都是删除队列的头元素,区别在于:
add方法在队列满的情况下抛异常,而offer方法则返回false.
remove方法在队列为空时抛异常,poll方法将返回null.
15.迭代器 Iterator 是什么?
Iterator是个接口,它提供了很多对元素进行迭代的方法.迭代器可以在迭代过程中删除底层集合的元素,可以直接调用Iterator的remove()方法来删除. 因为在Conllection接口中定义了获取集合迭代器的方法,所以每一个集合都包括了可以返回迭代器实例的方法.
16.Iterator 怎么使用?有什么特点?
每个集合都可以用iterator()方法一个Iterator实例.
使用next()方法获取序列中的下一个元素,使用hasNext()方法检查序列中是否有元素
使用remove()方法将迭代器新返回的方法删除.
特点:Iterator将集合的遍历和其底层的结构分离.
17. Iterator 和 ListIterator 有什么区别?
ListIterator是Iterator的子接口,用于扩展Iterator.
在Iterator中,我们只能向前移动,无法操纵或者修改集合中的元素.ListIterator弥补了这种缺点
区别: 1.范围不同,Iterator适用于所有集合,而ListIterator只适用于List及其子类
2.ListIterator有add方法可以添加元素,Iterator则不行.
3.ListIterator可以实现双向遍历,Iterator则不行.
4.ListIterator可以实现对象的修改,Iterator不行
5.ListIterator可以获取集合中的所有,Iterator不行.
18.比较HashSet、LinkedHashSet、TreeSet三者的异同?
HashSet是Set接口的主要实现类,HashSet的底层是HashMap,是线程不安全的,LinkedHashSet是HashSet的子类,能够按照添加顺序进行遍历,TreeSet底层使用红黑树,能够按照添加对象的指定属性进行排序,排序的方式有自然排序和定制排序。