Java集合框架(常见面试题总结)

1、List接口的实现类

(1)数组列表ArrayList和链表LinkedList:

  • ArrayList实现了可变的数组,允许保存所有元素,包括null,并可以根据索引位置对集合进行快速的随机访问。缺点是向指定的索引位置插入或删除对象的速度较慢。
  • LinkedList类采用链表结构保存对象,这种结构的优点是便于向集合中插入和删除对象,但对于随机访问集合中的对象效率较低。

(2)访问实现了list接口的集合中元素的方法:

  • 使用迭代器
  • 使用get和set方法随机的访问每个元素(随机是指可以访问任意一个元素)

3)Arraylist与Linkedlist异同:

  • Arraylist与Linkedlist都是不同步的,也就是不保证线程安全。
  • Arraylist 底层使用的是Object数组,适用于快速随机访问;LinkedList 底层使用的是双向链表数据结构,适用于元素插入删除。
  • Vector类的所有方法都是同步的,Arraylist不是同步的,所以在不需要保证线程安全时时建议使用Arraylist

2、散列集

数组和链表是有序的(这里的有序是指插入有序,可以指定插入的位置,而不是按大小什么的排序)。如果不在乎元素的顺序,可以有几种快速查找元素的数据结构。其缺点是无法控制元素出现的次序。set集合是没有重复元素的元素集合。set接口常用的实现类有HashSet和TreeSet:

  • HashSet类实现set接口,由哈希表支持(实际上是一个HashMap实例)支持。它不保证Set的迭代顺序,set集合元素允许为null。HashSet是无序的,不能保证取出顺序就是放置顺序;
  • TreeSet类实现了Set接口,遍历集合时可以按自然顺序递增排序,排序是由红黑树完成的。

3、Map接口的实现类有HashTable、HashMap、TreeMap

(1)Map没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个 value。Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value集合。

2HashMap是基于哈希表的Map接口的实现,允许null值和null键,但必须保证键的唯一性。此类不保证映射的顺序,特别是不保证该顺序恒久不变。TreeMap集合中的映射关系是有序的,不允许键对象是null。

  • HashMap 底层是 数组和链表 结合在一起使用也就是 链表散列。HashMap的实现方式是数组链,不同的对象根据其哈希码(hashCode方法的返回值)找到对应的数组下标,然后存入数组。两个对象的hashCode相同,但实例不一定相同。反过来如果两个对象实例相同,则hashCode一定相同
  • HashMap 是非线程安全的,HashTable 是线程安全的,他们创建时容量初始值不同,且HashMap允许null键和null值

4、Iterator和ListIterator之间的区别

Iterator认为是在两个元素之间,当调用next时,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用

(1)我们可以使用Iterator来遍历Set和List集合,而ListIterator只能遍历List。

(2)Iterator只可以向前遍历,而LIstIterator可以双向遍历。

(3)ListIterator从Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。

5、HashMap是如何工作的?

 HashMap在Map.Entry静态内部类实现中存储key-value对。HashMap使用哈希算法,在put和get方法中,它使用hashCode()和equals()方法。当我们通过传递key-value对调用put方法的时候,HashMap使用Key hashCode()和哈希算法来找出存储key-value对的索引。Entry存储在LinkedList中,所以如果存在entry,它使用equals()方法来检查传递的key是否已经存在,如果存在,它会覆盖value,如果不存在,它会创建一个新的entry然后保存。当我们通过传递key调用get方法时,它再次使用hashCode()来找到数组中的索引,然后使用equals()方法找出正确的Entry,然后返回它的值。

HashMap的实现方式是数组链,不同的对象根据其哈希码(hashCode方法的返回值)找到对应的数组下标,然后存入数组。两个对象的hashCode相同,但实例不一定相同。反过来如果两个对象实例相同,则hashCode一定相同

6、HashMap的底层实现

JDK1.8 之前 HashMap 底层是 数组和链表 结合在一起使用也就是 链表散列。HashMap 通过 key 的 hashCode 经 过扰动函数处理过后得到 hash 值,然后通过 (n - 1) & hash 判断当前元素存放的位置(这里的 n 指的是数组的 长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的 话,直接覆盖,不相同就通过拉链法解决冲突。(两个对象的hashCode相同,但实例不一定相同。反过来如果两个对象实例相同,则hashCode一定相同) 所谓扰动函数指的就是 HashMap 的 hash 方法。使用 hash 方法也就是扰动函数是为了防止一些实现比较差的 hashCode() 方法 换句话说使用扰动函数之后可以减少碰撞。

所谓 “拉链法” 就是:将链表和数组相结合。也就是说创建一个链表数组,数组中每格就是一个链表。若遇到哈希 冲突,则将冲突的值加到链表中即可。

 

JDK1.8之后 ,相比于之前的版本, JDK1.8之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。TreeMap、TreeSet以及JDK1.8之后的HashMap底层都用到了红黑树。红黑树就是为了解决二叉查找树的缺 陷,因为二叉查找树在某些情况下会退化成一个线性结构。

7、HashMap 和 Hashtable 的区别

(1) 线程是否安全: HashMap 是非线程安全的,HashTable 是线程安全的;HashTable 内部的方法基本都经过 synchronized 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap 吧!);

(2) 效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。另外,HashTable 基本被淘汰,不要在代码中使用它

(3) 对Null key 和Null value的支持: HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键 所对应的值为 null。但是在 HashTable 中 put 进的键值只要有一个 null,直接抛出 NullPointerException。

(4)初始容量大小和每次扩充容量大小的不同 : ①创建时如果不指定容量初始值,Hashtable 默认的初始大小为 11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小(HashMap 中的 tableSizeFor() 方法保证,下面给出了源代码)。也就是说 HashMap 总是使用2的幂作为哈希表的大小,后面会介绍到为什么是2的幂次方。

(5)底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。

8、ConcurrentHashMap 和 Hashtable 的区别

9、 集合框架底层数据结构总结

1. List

  • Arraylist: Object数组
  • Vector: Object数组
  • LinkedList: 双向链表(JDK1.6之前为循环链表,JDK1.7取消了循环) 详细可阅读JDK1.7-LinkedList循环链表优化

2. Set

  • HashSet(无序,唯一): 基于 HashMap 实现的,底层采用 HashMap 来保存元素
  • LinkedHashSet: LinkedHashSet 继承与 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类 似于我们之前说的LinkedHashMap 其内部是基于 Hashmap 实现一样,不过还是有一点点区别的。
  • TreeSet(有序,唯一): 红黑树(自平衡的排序二叉树。)

3.Map

  • HashMap: JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希 冲突而存在的(“拉链法”解决冲突)。JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默 认为8)时,将链表转化为红黑树,以减少搜索时间
  • LinkedHashMap: LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以 保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。详细可以查看: 《LinkedHashMap 源码详细分析(JDK1.8)》
  • HashTable: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
  • TreeMap: 红黑树(自平衡的排序二叉树)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值