java面试题系列(二)集合
java面试中,集合基本上是重中之重,不管是初中高级程序员,都是必考的点。因为集合可以考察面试者的诸如对java语言特性、对数据结构的知识面的了解程度。而且,java集合面试回答的重点,就是自己心里要有一套完整的体系概念,问一个问题你要把整个集合说出来才行。从而体现你对该知识体系有良好的理解和概念(不限于集合,当然,也不限于Java)
集合综合问题:
1.说一下java的集合框架(思路:不建议把每个类型的实现类和接口都说出来,第一个原因是如果回答太详细,比如每个接口作用和实现类说得完完整整,那明显感觉像背的【当然了解源码还是对提升编码能力有帮助的】,而且也没有考察性。第二个原因是话都给说完了还问啥?还有,队列不建议说,因为问线程方面基本上会再次问)
java集合是指一组元素的集合,他下面有几大类型,
List,一组有序、可重复的对象的集合
Set,一组无序,不可重复的对象的集合(可能会问:那你知道有有序的Set吗)
Map,k-value键值对元素的集合
2.说一下collection(可以说下子类了,因为这个范围还是缩小了的小的)
collection是集合框架顶层接口,代表了一组元素的集合。他下面有几大类型
List,一组有序、可重复的对象的集合,实现类有底层数组实现的ArrayList,线程安全的数组实现的Vector,底层链表实现的LinkedList(可以提及一下运用场景:比如前者更适合根据下标随机查找元素这些,不过接下来可能问你为什么他适合这个场景,后面讲)
Set,一组无序,不可重复的对象的集合,实现类有基于散列表的无序、不可重复的HashSet(实际为HashMap),基于红黑树的,有序的TreeSet(如何定义排序规则?)
3.说一下map(这个被外企问到过几次,说实现类和各自特点和使用场景。注意:conrrentHashmap是并发包下面的,只有单独问到才说)
Map是一组k-value键值对元素的集合,他下面的实现类有:
基于散列表的一组无序、不可重复的元素的集合的HashMap
HashTable,所有方法都同步的HashMap
基于红黑树的有序的TreeMap以及子类properties类
以及有序的hashmap:LinkedHashMap
集合基本问题
1.为啥要使用集合框架(用了有什么好处?)
提高代码复用性和可操作性,代码方便维护这些(毕竟人为啥要吃饭呢)
2.*什么是快速失败?什么是安全失败(微服务调用也有这个概念,意思完全不同)
前者指在集合迭代的时候删除元素从而导致集合抛异常,原因是集合维持一个modCount变量,集合改变时该变量改变从而导致异常(并发)
后者指复制副本进行迭代删除从而不会影响原集合(并发包下的)
3.迭代器是什么
用来遍历集合内元素类,每个集合类自带实现,通过移动指针到下一个元素来遍历
4.*为何 Map 接口不继承 Collection 接口
因为map属于集合框架的一部分,但是他不属于集合,而是一组key-value键值对,不符合一组对象的定义(前文提到的是元素)。且继承了毫无意义
5.Iterator 和 ListIterator 的区别是什么?
前者所有集合实现类都有,后者为list特有且可以支持向前迭代
6.集合中泛型有什么用
泛型是将对象类型参数化,用于在编译前(编码时)提供检查类型是否正确。编译时将擦除类型
7.Comparable与Compartor的区别和作用
两者都是用于集合排序。
不同是:前者是用于定义相同一类对象互相之间的比较规则(实现comparTo方法)
后者是用于在collections.sort方法中重写(匿名内部类)来定义集合中元素的排序规则
8.集合可以存入基本数据类型吗?
不能,泛型不支持基础类型。且不符合集合的定义(一组对象的集合)
List
1.ArrayList的原理是什么,适用于哪些场景
底层为动态数组实现的ArrayList,适用于根据下标随机访问元素
2.为什么适合根据下标访问元素
因为底层的数组在内存中是一串连续的内存空间,CPU操作效率高。而LinkedList则需要遍历链表找到对应下标元素
3.LinkedList的原理是什么,适用于哪些场景
底层为链表实现的LinkedList,每个节点持有前后节点的对象的引用,适合删除元素(忽略查找要删除的元素时间的情况下),只需将前后节点的引用修改为对方即可删除,不必像ArrayList一样中间删除元素要移动后面元素对其一样
4.ArrayList 和 Vector 有何异同点?
同为动态数组来实现的,不同的是:前者扩容时1.5倍,后者两倍。前者线程不安全,后者所有方法都有同步关键字(效率当然是前者高后者低喽)
5.ArrayList和LinkedList区别(结合上面几点答,底层数据结构、各自适用场景)
6.ArrayList和LinkedList是线程安全的吗,如果不是应该怎么做
不是,可以采用并发包下的容器组件(CopyWriteArrayList等)
7.List元素去重说一下
可以转化为set(HashSet),或者存入HashMap(一样的思路)
Set
1.说下set
set是一组无序,不可重复的对象的集合,实现类有基于散列表的无序、不可重复的HashSet(实际为HashMap),基于红黑树的,有序的TreeSet。有序的HashSet:LinkedHashSet
2.HashSet是怎么实现的
通过HashMap,key为元素,value为占位符
3.set有哪些应用场景
元素去重、随机排序元素(随机但是固定一种)
4.set都是无序的吗?(或:如何实现有序的set)
TreeSet、LinkedHashSet是有序的set。其中前者可以定义排序规则,后者保留插入顺序
5.map中如何取出key的集合
使用keySet方法取出包含所有key的set集合
Set待补充(因为真的很少问到)
Map
集合算是java的面试重点了。这个真的是集合中的重点了
1.说一下Map(参照上面)
Map是一组k-value键值对元素的集合,他下面的实现类有:
基于散列表和链表的一组无序、不可重复的元素的集合的HashMap
HashTable,所有方法都有同步关键字的HashMap
基于红黑树的有序的TreeMap以及子类properties类
以及有序的hashmap:LinkedHashMap
HashMap相关
2.HashMap 说一下怎么实现的
通过一个散列表(数组)加链表实现的,也就是通过key的哈希值与(数组长度-1)做位与运算,得出元素应该存放的数组下标。(这里可以答是否哈希碰撞等)
3.如果检测到冲突,也就是哈希后计算的位置有元素怎么办?(哈希碰撞)
通过equals方法比较,如果相等则证明两个元素完全相同(哈希值和equals方法都相同了)。因为HashMap中每个节点(Entry)存放的是链表节点,所以把该元素放到链表头
4.哈希是什么
哈希是指一种算法。指将输入的值通过特定的算法计算为一串固定长度的字符串
5.为什么说哈希碰撞过多会导致效率变低?
因为如果哈希碰撞过多,可能会导致许多元素都在一个位置,也就是一个链表中。HashMap取出时每次都要遍历链表,而链表遍历是相当花时间的
6.除了链表法,还有哪些处理哈希冲突的方法
再次寻址法:再哈希一次。
7.*HashMap为什么推荐传入初始容量为2的幂次方?
因为HashMap默认采用的哈希算法是元素key的哈希值对(数组长度-1)做位与运算,(注:2的幂次方-1的二进制数为:每个位上都为1。位与:都1为1,其他为0)。如果不是二的幂次方,位运算则必定会有位为0,那么key始终在这位为0始终为0,从而导致有一部分元素存在同一位置,增大碰撞风险 不过就算你传入不是2的幂次方,他也会取最接近传入的数 的2的幂次方(大于该数的2的幂次方)作为默认初始容量。
8.HashMap的扩容机制是什么?
当元素个数到达(最大容量*加载因子)个数时,将数组扩大为原来两倍,所有元素重新计算哈希值并放入对应位置
9.jdk1.7与1.8中HashMap有什么区别
1.7中碰撞后采用链表处理冲突,遍历链表查找效率差。1.8后链表长度超过8会转化为红黑树,查询效率大大提升
10.为啥重写了equals方法还要必须重写hasCode方法
第一个是因为规范和共识(废话),equals方法是判断两个对象是否相同的方法,如果两个对象完全相同,哈希值也必须相同,第二点是因为如果两个对象equal相等,那么他们应该是两个相同的对象,否则两个相等的对象,却放在不同位置,浪费空间和性能。HashSet也会完全失去作用
11.如何遍历map
第一种方法:通过keySet方法取出键的set集合,取出set每个元素进行map遍历,第二种方法:通过entrySet()方法得到键值对对象Entry的集合,循环遍历该对象取出键值
12.*HashMap中有哪些关键的变量
加载因子、初始容量
13.为什么加载因子设为0.75?
加载因子是指当HashMap满了加载因子的比例时会进行扩容。因为是基于碰撞和空间的考量的一个考虑。如果设的太大,则当HashMap快装满时才会扩容,这样会产生大量的哈希碰撞。如果设置的小,则HashMap距离装满差很大一截就开始扩容,这样会导致一部分空间一直不会得到使用,浪费空间
14.HashMap是线程安全的吗(为什么不安全)
不是线程安全的。当扩容时替换指针和重新计算哈希可能会导致链表循环引用
15.既然线程不安全,那你有什么解决方法吗?
如果不考虑效率,可以采用所有方法增加了同步关键字的HashTable。当然,最优解则为并发包Courrent下的CourrentHashMap。
16.HashTable和HashMap区别
前者是线程安全的,每个方法都加了同步关键字,key不能为null。后者则相反。。
17.HashTable为啥效率低(考HashTable源码)
因为同步了get和set,如果大量读取会导致大量阻塞
18.HashMap在什么时候会转化为红黑树,什么时候会退化为链表
(桶)链表长度大于等于8时
CourrentHashMap相关
1.CourrentHashMap是什么
是jdk1.5增加的并发包下面的类,主要用于处理并发下map的问题
2.相比于HashMap和HashTable,有什么区别
由于采用了分段锁,把散列表(数组)划分为一个个段,每个段单独持有有一把锁,支持16个线程并发操作,比起前者并发安全性好,比起后者效率高
3.jdk1.7与1.8有什么区别(要回答map1.7和1.8区别)
1.7中采用分段锁,写时只锁该段读写,从而并发安全。1.8以后采用synchronized+CAS,对链表和红黑树加关键字synchronized,再用修改CAS比较重试,大大的增加了并发安全和效率
4.并发包待续
TreeMap
1.是什么
是一个支持根据key来进行元素排序的有序map
2.怎么使用
通过对象实现compare接口重写比较方法,如果返回1和2则为两个元素比较结果,0则两个元素相同
集合相关问题
1.集合如何实现排序
通过工具类collections.sort方法,默认为比较key的大小。如果要根据对象某个属性进行比较,则需传入的对象实现compare类,自定义排序规则
2.为什么操作Arrays.asList()方法的list时会有问题(为什么该方法不支持add和删除)
该方法作用是将数组转化为list,但只是用一个内部实现类持有该数组。所以。。
3.HashMap是有序的吗?我想要有序的HashMap怎么办
无需的,根据哈希值计算肯定是无序存储的。可以使用LinkedHashMap。用一个链表来维持元素顺序的hashmap
其他参考源码系列:https://mp.csdn.net/postedit/103359042 没写完
待补充。。。