栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java集合面试题

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java集合面试题

目录

1、什么集合

2、集合和数组的区别

3、java集合的基础接口有哪些

4、List、Set、Map集合的特点

5、Collection 和 Collections 的区别

6、集合框架底层数据结构

7、什么是迭代器(Iterator)

8、Iterator 和ListIterator 的区别是什么

9、说出 ArrayList,Vector, LinkedList 的存储性能和特性

10、ArrayList 与 LinkedList 区别

11、ArrayList和Vector区别

12、HashMap 和 Hashtable 的区别

13、HashSet 和 TreeSet 的区别

14、ArrayList底层实现原理

15、HashMap底层实现原理

HashMap在jdk7中的实现原理

HashMap在jdk8中相较于jdk7在底层实现方面的不同

hashmap常用的方法:

16、ConcurrentHashMap 源码分析

17、线程安全的集合有哪些

早期线程安全的集合

现在常用的线程安全的集合

18、循环遍历集合的方法

1、什么集合

集合是一个存放数据的容器,集合类存放的都是对象的引用,而不是对象的本身。

集合类型主要有三种:list、set、map

2、集合和数组的区别

数组的长度是固定的;集合的长度是可变的。

数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。

数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。

3、java集合的基础接口有哪些

Collection、Map、Queue等。

Collection为集合层级的根接口,子接口包含List、Set集合。

Map:map接口的实现类主要有:Hashmap、Treemap、Hashtable、ConcurrentHashMap以及Properties。

Set:set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等

List:list接口的实现类主要有ArrayList、LinkedList、Stack以及Vector等

4、List、Set、Map集合的特点

List:一个有序集合,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector。
Set:一个无序集合,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及 TreeSet。
Map是一个键值对集合,存储键、值和之间的映射。 Key无序,唯一;value 不要求有序,允许重复。Map没有继承于Collection接口,从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。

5、Collection 和 Collections 的区别

Collection ,是集合类的上级接口,继承与他的接口主要有 Set 和List 。

Collections ,是针对集合类的一个工具类,它提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。

6、集合框架底层数据结构

1、List

ArrayList :Object 数组。

Vector :Object 数组。

LinkedList :双向链表(JDK6 之前为循环链表,JDK7 取消了循环)。

2、Set

HashSet :无序,唯一,基于 HashMap 实现的,底层采用 HashMap 来保存元素。

LinkedHashSet :LinkedHashSet 继承自 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类似于LinkedHashMap 其内部是基于 HashMap 实现一样,不过还是有区别的。

TreeSet :有序,唯一,红黑树(自平衡的排序二叉树)。

3、Map

HashMap :JDK8 之前,HashMap 由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。JDK8 以后,在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8 )时,将链表转化为红黑树,以减少搜索时间。

LinkedHashMap :LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。

Hashtable :数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的。

TreeMap :红黑树(自平衡的排序二叉树)。

7、什么是迭代器(Iterator)

Iterator 接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素。克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。因此,应该由集合类的具体实现来决定如何被克隆或者是序列化。

8、Iterator 和ListIterator 的区别是什么

Iterator 可用来遍历 Set 和 List 集合,但是 ListIterator 只能用来遍历 List。 Iterator 对集合只能是前向遍历,ListIterator 既可以前向也可以后向。 ListIterator 实现了 Iterator 接口,并包含其他的功能,比如:增加元素,替换元素,获 取前一个和后一个元素的索引,等等。

9、说出 ArrayList,Vector, LinkedList 的存储性能和特性

ArrayList 和 Vector 都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增 加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作, 所以索引数据快而插入数据慢,Vector 由于使用了 synchronized 方法(线程安全),通常性能 上较 ArrayList 差,而 LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或 后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。

10、ArrayList 与 LinkedList 区别

ArrayList 是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高。因为地址连续,ArrayList 要移动数据,所以插入和删除操作效率比较低。

LinkedList 基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址。对于新增和删除操作 add 和 remove ,LinedList 比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景。因为 LinkedList 要移动指针,所以查询操作性能比较低。

在绝大对数场景业务下,一般都是使用Arraylist。

11、ArrayList和Vector区别

1、Vector 是多线程安全的,Vector 类中的方法很多有synchronize进行修饰,这样就导致了 Vector 在效率上无法与 ArrayList 相比。(一般情况下不会使用Vector)

2、两个都是采用的线性连续空间存储元素,但是当空间不足的时候,两个类的增加方式是不同。

3、Vector 可以设置增长因子,而 ArrayList 不可以。

12、HashMap 和 Hashtable 的区别

1、Hashtable 继承 Dictionary ,HashMap 继承的是 Map 接口。

2、HashMap 去掉了 Hashtable 的 contains 方法,但是加上了 containsValue 和 containsKey 方法。

3、HashMap 允许空键值,而 Hashtable 不允许。

4、HashTable 是同步的,而 HashMap 是非同步的,效率上比 HashTable 要高。也因此,HashMap 更适合于单线程环境,而 HashTable 适合于多线程环境。

5、HashMap 的迭代器(Iterator)是 fail-fast 迭代器,HashTable的 enumerator 迭代器不是 fail-fast 的。

6、HashTable 中数组默认大小是 11 ,扩容方法是 old*2+1 ,HashMap 默认大小是 16 ,扩容每次为 2 的指数大小。

现在一般不会用hashtable,与Vector一样,都是比较旧的遗留类,内部实现很多没优化和冗余,虽然是线程安全的集合,但是现在有替代他的集合 如ConcurrentHashMap 。

13、HashSet 和 TreeSet 的区别

HashSet 是用一个 hash 表来实现的,因此,它的元素是无序的。添加,删除和 HashSet 包括的方法的持续时间复杂度是 O(1) 。

TreeSet 是用一个树形结构实现的,因此,它是有序的。添加,删除和 TreeSet 包含的方法的持续时间复杂度是 O(logn) 。

一般对于在 Map 中插入、删除和定位元素这类操作,HashMap 是最好的选择。然而,你需要对一个有序的 key 集合进行遍历, TreeMap 是更好的选择。

14、ArrayList底层实现原理

1) ArrayList 是一种变长的集合类,基于定长数组实现,使用默认构造方法初始化出来的 容量是 10(1.7 之后都是延迟初始化, 即第一次调用 add 方法添加元素的时候才将 elementData 容量初始化为 10)。

2) ArrayList 允许空值和重复元素,当往 ArrayList 中添加的元素数量大于其底层数组容 量时,其会通过扩容机制重新生成一个更大的数组。ArrayList 扩容的长度是原长度的 1.5 倍 

3) 由于 ArrayList 底层基于数组实现,所以其可以保证在 O(1) 复杂度下完成随机查找操作。

4) ArrayList 是非线程安全类,并发环境下,多个线程同时操作 ArrayList,会引发不可预知的异常或错误。

5) 顺序添加很方便

6) 删除和插入需要复制数组,性能差(可以使用 LinkindList)

7) Integer.MAX_VALUE - 8 :主要是考虑到不同的JVM,有的JVM会在加入一些数据头,当 扩容后的容量大于MAX_ARRAY_SIZE,我们会去比较最小需要容量和MAX_ARRAY_SIZE做比较, 如果比它大, 只能取Integer.MAX_VALUE,否则是 Integer.MAX_VALUE -8。 这个是从 jdk1.7 开 始才有的

15、HashMap底层实现原理

HashMap在jdk7中的实现原理

HashMap对象在实例化后,底层创建了一个长度为16的一维数组 Entry[ ] table

当执行方法 put(key1,value1) 添加数据时,HashMap底层的实现原理如下(此前可能已经执行过多次put()方法):

首先,调用key1所在类的hashCode()计算key1的哈希值,此哈希值经过底层算法的计算以后,可以得到在Entry数组中的存放位置,接下来又分为三种情况。

情况1:如果此位置上的数据为空,此时的key1-value1添加成功。

情况2:如果此位置上数据不为空(意味着此位置上存在一个或多个数据(多个数据以链表的形式存在)),则比较key1和已经存在的数据的哈希值,如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功,即key1-value1和原来的数据会以链表的形式存储。

情况3:与情况二类似,在比较key1和已经存在的数据的哈希值时,如果key1的哈希值和某个已经存在的数据(如key2-value2)的哈希值相同,则调用key1所在类的equals()方法,返回key1和key2的比较结果,如果返回的是false,此时key1-value1添加成功,同样也是和原来的数据以链表的形式存储;如果返回的是true,则会使用value1替换value2。

在不断添加数据的过程中,会涉及到数组的扩容问题。当添加数据超出临界值(且数据要存放的位置非空)时,需要对数组扩容。默认的扩容方式:扩容为原来容量的2倍,并将原来的数据复制过来。

HashMap在jdk8中相较于jdk7在底层实现方面的不同

1、使用空参构造器创建HashMap对象时,底层没有直接创建一个长度为16的数组。
2、jdk8底层存储数据的数组使用的是Node[ ],而不是Entry[ ] 。
3、jdk8在首次调用put()方法时,底层才会创建长度为16的数组。
4、jdk7中底层存储数据的结构是:数组+链表。jdk8中底层存储数据的结构是:数组+链表+红黑树。
5、当存储数据形成链表时,链表的结构不相同,jdk7的链表结构是:新的数据指向旧的数据。jdk8的链表结构是:旧的数据指向新的数据。
6、当底层数组的某一个索引位置上的元素以链表形式存在的数据个数大于8 ,且当前数组的长度大于64时,此时这个索引位置上的数据改为使用红黑树存储。

hashmap常用的方法:

添加:put(Object key,Object value)
删除:remove(Object key)
修改:put(Object key,Object value)
查询:get(Object key)
长度:size()

16、ConcurrentHashMap 源码分析

ConcurrentHashMap 所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段 数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访 问。有些方法需要跨段,比如 size()和 containsValue(),它们可能需要锁定整个表而而不仅仅是 某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很 重要的,否则极有可能出现死锁,在 ConcurrentHashMap 内部,段数组是 final 的, 并且其成 员变量实际上也是 final 的,但是,仅仅是将数组声明为final 的并不保证数组成员也是 final 的,这需要实现上的保证。这可以确保不会出现死锁,因为获得锁的顺序是固定的。

ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成。Segment 是一种可 重入锁 ReentrantLock,在 ConcurrentHashMap 里扮演锁的角色,HashEntry 则用于存储键值 对数据。一个 ConcurrentHashMap 里包含一个 Segment 数组,Segment 的结构和 HashMap 类似,是一种数组和链表结构, 一个 Segment 里包含一个 HashEntry 数组,每个 HashEntry 是一个链表结构的元素, 每个 Segment 守护者一个 HashEntry 数组里的元素,当对 HashEntry 数组的数据进行修改时,必须首先获得它对应的 Segment 锁。

17、线程安全的集合有哪些

早期线程安全的集合

1、Vector

Vector和ArrayList类似,是长度可变的数组,与ArrayList不同的是,Vector是线程安全的,它给几乎所有的public方法都加上了synchronized关键字。由于加锁导致性能降低,在不需要并发访问同一对象时,这种强制性的同步机制就显得多余,所以现在Vector已被弃用。


2.HashTable

HashTable和HashMap类似,不同点是HashTable是线程安全的,它给几乎所有public方法都加上了synchronized关键字,还有一个不同点是HashTable的K,V都不能是null,但HashMap可以,它现在也因为性能原因被弃用了

现在常用的线程安全的集合

ConcurrentHashMap(解释看第16)

CopyOnWriteArrayList和CopyWriteArraSet:它们是加了写锁的ArrayList和ArraySet,锁住的是整个对象,但读操作可以并发执行。

除此之外还有ConcurrentSkipListMap、ConcurrentSkipListSet、ConcurrentLinkedQueue、ConcurrentLinkedDeque等。

18、循环遍历集合的方法

迭代器~集合特有的遍历方式
for循环的遍历方式
增强for~最方便的遍历方式

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/973384.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号