Java集合框架及其面试重点

目录

目录

一、集合框架概述

二、面试重点

1、List接口

介绍Java的List,ArrayList与LinkedList的区别

Array(数组)和ArrayList有何区别?什么时候更适合用Array?

List是线程安全的吗?如果要线程安全要怎么做?

怎么给List排序?

通过Array.asList获得的List有何特点,使用时应该注意什么?

List和Array之间如何互相转换?

ArrayList的删除,需要注意List删除后下标变化的坑(用Iterator的写法)

什么是fail-fast,什么是fail-safe,有什么区别吗?

List的迭代方式有哪些?

在迭代一个集合的时候,如何避免ConcurrentModificationException?

2、set接口

HashSet是如何保证数据不可重复的?

HashSet 底层数据结构

LinkedHashSet 底层数据结构及其特点

TreeSet的底层数据结构及其特点

3、map接口

HashMap的底层数据结构

HashMap与HashTable的区别?

HashMap是否线程安全,体现在什么地方?

HashMap的扩容操作是怎么实现的?

为什么数组长度要保持为2的幂次方?

HashMap是怎么解决哈希冲突的?

HashMap为什么不直接使用hashCode()处理后的哈希值直接作为table的下标?

HashMap在JDK1.7和JDK1.8中有哪些不同?

为什么HashMap中String、Integer这样的包装类适合作为Key?我们能否使用任何类作为Map的key?如果能需要注意哪些问题

HashMap和HashTable有何不同?

ConcurrentHashMap和Hashtable的区别?

ConcurrentHashMap在JDK1.7和JDK1.8中有哪些不同?

4、Queue接口

BlockingQueue的特点?

队列和栈的区别?

5、Collection框架

Collection框架中实现比较要实现什么接口

集合在遍历过程中是否可以删除元素,为什么迭代器就可以安全删除元素

Enumeration和Iterator接口的区别?

并发集合类是什么?

如何从给定集合那里创建线程安全的集合?

Collection和Collections的区别

Iterator和Iterable接口的区别


一、集合框架概述

Java集合框架是一个很重要的内容,面试中也是属于必考的部分,那么首先,什么是集合?什么是集合框架呢?集合框架有什么优点?

通常我们把具有相同性质的一类东西,汇聚成一个整体,就可以称为集合。集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。

集合框架的优点:

(1)使用核心集合类降低开发成本,而非实现我们自己的集合类。

(2)随着使用经过严格测试的集合框架类,代码质量会得到提高。

(3)通过使用JDK附带的集合类,可以降低代码维护成本。

(4)复用性和可操作性。

 

集合框架常用实现类如下:

在集合框架中,主要可以分为三个大类:list(列表)、set(集)、map(映射)

list是有序的,元素按照添加进list的顺序排序,元素可以重复,访问时可以根据元素的索引来访问,使用Iterator时的遍历顺序和元素添加的顺序一致;

set是无序的,因此使用迭代器(Iterator)的时候,不能保证元素的遍历顺序,但是可以保证所有元素被遍历;此外,set中不允许出现重复的元素,访问的时候只能通过元素本身来访问(这也是元素不能重复的原因);

map保存的是<key,value>键值对,key不能重复,但是value可以重复,访问时只能根据key来访问value,使用Iterator时,对key进行遍历,然后根据每个key访问相应的value;

此外,还有queue接口和一些在并发中涉及到的集合。

 

二、面试重点

1、List接口

List接口是Collection接口的子接口,通常用于表示有序的数组(可以动态扩容),链表,队列,栈等。其实现类主要有3个:ArrayList、LinkedList 和 Vector(线程安全)。

面试中主要涉及的问题有:

介绍Java的List,ArrayList与LinkedList的区别

ArrayList与LinkedList、Vector的区别

Array(数组)和ArrayList有何区别?什么时候更适合用Array?

区别:

  • 数组的长度固定不变,而ArrayList是动态数组,在容量不够是会进行1.5倍的扩容
  • 数组的元素可以是基本类型或者对象,但ArrayList只能是对象(直接放入的基本类型经过自动装箱成为包装类对象)
  • 数组中所有元素类型必须是一样的,但是ArrayList可以存储Object对象,因此如果把泛型类型限制为Object则可以存储不同类型的元素
  • ArrayList比数组的方法更加丰富,还可以有自己的迭代器对象

使用场景:

  • 当集合长度固定,并且只需要对数组进行简单的随机读写,使用数组,因为数组占用内存更低;如果集合长度可变,并且需要有插入、删除等操作,选择ArrayList,因为ArrayList集成了相关操作,并且可以自动扩容。当然如果插入和删除的操作十分的频繁还是使用LinkedList。
  • 当存储的时基本数据类型,因为ArrayList不支持基本数据类型,需要进行自动装箱和拆箱,效率相对下降,因此尽量选择数组。

List是线程安全的吗?如果要线程安全要怎么做?

实现list实现类的线程安全:

  • List接口下的实现类,只有Vector及其子类Stack时线程安全的,其他都是非线程安全的,因此可以使用Vector来代替ArrayList
  • 可以使用Collections.synchronizedList(List<T> list)方法包装list的实现类即可,同样的可以用Collections.synchronizedSet(Set<T> set)、Collections.synchronizedMap(Map<K,V> m)、Collections.synchronizedCollection(Collection<Object>)方法包装集合框架的其他非线程安全实现类来实现线程安全的类。

两种方法的区别:

  • 如果使用add方法,那么他们的扩容机制不一样(类似arraylist和Vector的区别)。

  • SynchronizedList可以通过Collections.synchronizedList(List<T> list,Object mutex)指定锁定的对象。通过Collections的源代码也可以看出Collections.synchronizedList返回的是内部类SynchronizedList,其中同步的实现是通过synchronized(mutex)同步代码块实现的,可以认为Collections.synchronizedList锁粒度是同步代码块。而Vector的锁粒度是同步方法。

  • SynchronizedList有很好的扩展性和兼容功能。他可以将所有的list子类转成线程安全的类。

  • 使用SynchronizedList的时候,进行遍历时需要手动进行同步处理,这是因为Collections.synchronizedList的迭代器iterator并没有做同步处理,而是直接使用了list的iterator。

怎么给List排序?

list、set、map的排序

通过Array.asList获得的List有何特点,使用时应该注意什么?

asList()方法返回的list的特点:

Array.asList()方法的作用是将数组转换为list集合,但是通过其源代码可以发现,Array.asList()返回的是Arrays的一个内部类,该内部类只是实现了AbstractList接口,但是其后台仍然是数组的数据结构,也就是说,得到的只是原来数组的视图List,而没有实现list集合的add和remove等修改方法,因此如果对他进行增删操作会报UnsupportOperationException异常。

具体案例参考:https://www.cnblogs.com/hoobey/p/6661294.html

如何实现得到真的list:

用ArrayList的构造器可以将其转变成为一个真正的ArrayList

Integer[] a={1,2,3,4,5};
ArrayList al= new ArrayList(Arrays.asList(a));

需要注意的是,Array.asList()方法对基本数据类型的数组是无效的:如下代码所示,对于基本数据类型,ArrayList中的元素只有一个,就是数组本身。

int[] a={1,2,3,4,5};
ArrayList al= new ArrayList(Arrays.asList(a));
System.out.println(al.size());
//返回:1

List和Array之间如何互相转换?

  • 数组(Array)转list:Array.asList()方法,同上
  • list转数组(Array):list.toArray()方法

ArrayList的删除,需要注意List删除后下标变化的坑(用Iterator的写法)

元素删除的集中方法及其注意事项

什么是fail-fast,什么是fail-safe,有什么区别吗?

fail-fast 与 fail-safe 机制的原理与区别

List的迭代方式有哪些?

Collection集合实现类(list、set和queue)的集中迭代方式

在迭代一个集合的时候,如何避免ConcurrentModificationException?

什么时候会出现ConcurrentModificationException异常:

首先,ConcurrentModificationException异常是当条件modCount != expectedModCount成立时产生的,而这个比较是在迭代器(Iterator)的checkForComodification()方法中出现的,而Iterator的next()和remove()都调用了该方法,而expectedModCount是在获取迭代器的时候初始化的,也就是说,如果在调用Iterator的next()和remove()时modCount被修改,那么checkForComodification()方法会抛出ConcurrentModificationException异常。那么,什么情况会导致modCount被修改呢?add()、remove()操作都会。(foreach循环底层也是使用迭代器因此也hi出现该异常)

因此,在使用迭代器(Iterator)的时候使用list.add()、list.clear()和list.remove()方法都会导致ConcurrentModificationException异常。

详细代码参考:https://www.jianshu.com/p/00be866fcb18

如何避免ConcurrentModificationException异常:

  • 如果是remove()操作,使用迭代器(Iterator)自己的reemove()方法;listIterator有add()和remove()方法;
  • 使用Collections.synchronizedCollection() 去同步集合, 但是这样可能会影响效率,;
  • 使用concurrent包里的CopyOnWriteArrayList,  因为他的迭代器中没有checkForComodification;

 

2、set接口

set也是Collection接口的子接口,常见实现类有HashSet和TreeSet 。set集合中不允许有重复的元素是因为set集合用来比较两个元素是否相等时使用的是equals()方法,而不是“==”运算符,因此只要两个元素内容相同,就不能在一个set中共存,如果已经在set集合中存在了a元素,再使用add()方法添加a元素会返回false。

面试中主要涉及的问题有:

HashSet是如何保证数据不可重复的?

HashSet 底层数据结构

LinkedHashSet 底层数据结构及其特点

TreeSet的底层数据结构及其特点

 

3、map接口

map存储的是<key,value>键值对,而每个值又可以是一个map,以此类推,可以实现多层的映射。map接口常见的实现类有HashMap,TreeMap,HashTable等。map的key和set一样,不允许重复,但是value可以重复。从概念上来看,可以把List看做一种特殊的map,把List的索引当做key,把list的元素当做value,这样就可以形成键值对,但是事实上List和map并没有太多的关系。

面试中主要涉及的问题有:

HashMap的底层数据结构

HashMap与HashTable的区别?

HashMap是否线程安全,体现在什么地方?

HashMap的扩容操作是怎么实现的?

为什么数组长度要保持为2的幂次方?

hashCode的计算及其相关难点解答

HashMap是怎么解决哈希冲突的?

HashMap为什么不直接使用hashCode()处理后的哈希值直接作为table的下标?

HashMap在JDK1.7和JDK1.8中有哪些不同?

为什么HashMap中String、Integer这样的包装类适合作为Key?我们能否使用任何类作为Map的key?如果能需要注意哪些问题

HashMap和HashTable有何不同?

ConcurrentHashMap和Hashtable的区别?

ConcurrentHashMap在JDK1.7和JDK1.8中有哪些不同?

 

4、Queue接口

BlockingQueue的特点?

队列和栈的区别?

 

5、Collection框架

Collection框架中实现比较要实现什么接口

集合在遍历过程中是否可以删除元素,为什么迭代器就可以安全删除元素

Enumeration和Iterator接口的区别?

并发集合类是什么?

如何从给定集合那里创建线程安全的集合?

Collection和Collections的区别

Iterator和Iterable接口的区别

发布了56 篇原创文章 · 获赞 163 · 访问量 15万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章