Java集合框架常见面试题

1、简述List、Set和Map三者的区别

  • list(对付顺序的好帮手):List接口存储一组不唯一(可以有多个元素引用相同的对象),有序的对象
  • set(注重独一无二的性质):不允许重复的集合。不会有多个元素引用相同的对象。
  • map(用key来搜索的专家):使用键值对存储。Map会维护与key有关联的值。两个key可以引用相同的对象,但key不能重复,典型的key是String类型,但也可以是任何对象。

2、ArrayList和LinkedList区别

  1. 是否保证线程安全:ArrayList和LinkedList是线程不同步的,就是说不保证线程安全。
  2. 底层数据结构:ArrayList底层使用的是Object数组;LinkedList底层使用的是双向链表数据结构JDK1.6之前为循环链表,JDK1.7取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)
  3. 插入和删除是否受到元素位置的影响:①ArrayList采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。比如:执行add(E e)方法的时候,ArrayList会默认在指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定的位置i插入和删除元素的话(add(int index, E elment))时间复杂度就为O(n-i)。因为在进行上述操作的时候集合中第i个和第i个之后的(n-1)个元素都要执行向后移一位的操作。②LinkedList采用链表存储,所以对于add(E e)方法的插入,删除元素时间复杂度不受元素位置的影响,近似O(1),如果是要在指定位置i插入和删除元素的话((add(int index,E element))时间复杂度近似为O(n))因为需要先移动到指定位置再插入。
  4. 是否支持快速随机访问:LinkedList不支持高效的随机访问,而ArrayList支持,快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index))方法。
  5. 内存空间占用:ArrayList的空间浪费主要体现在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。

双向链表和双向循环链表:

双向链表: 包含两个指针,一个prev指向前一个节点,一个next指向后一个节点。

双向循环链表: 最后一个节点的 next 指向head,而 head 的prev指向最后一个节点,构成一个环。

3、ArrayList与Vector区别?为什么要用ArrayList代替Vector?

Vector的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。
ArrayList不是同步的,所以在不需要保证线程安全时建议使用ArrayList。

4、HashMap和HashTable的区别

  1. 线程是否安全:HashMap是非线程安全的,HashTable是线程安全的;HashTable内部的方法基本经过synchronized修饰。(如果你要保证线程安全就使用ConcurrentHashMap);
  2. 效率:因为线程是安全的,HashMap要比HashTable效率更高一点。另外,HashTable基本被淘汰,建议不要在代码中使用;
  3. 对Null key和Null value的支持:HashMap中,null可以作为键,这样的键只有一个,可以有一个或多个键对应的值为null。但是在HashTable中put进的键值只要有一个null,直接抛出NullPointException;
  4. 初始容量大小和每次扩充容量大小的不同:①创建时如果不指定容量初始值,HashTable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap默认的初始大小为16,之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么HashTable会直接使用你给定的大小,而HashMap会将其扩充为2幂次方大小。也就是说HashMap总是使用2的幂作为哈希表大小。
  5. 底层数据结构:JDK1.8以后的HashMap在解决哈希冲突时有了较大的变化,当链表大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。HashTable没有这样的机制。

5、HashMap 和 HashSet区别

如果你看过 HashSet 源码的话就应该知道:HashSet 底层就是基于 HashMap 实现的。(HashSet 的源码非常非常少,因为除了 clone() 、writeObject()、readObject()是 HashSet 自己不得不实现之外,其他方法都是直接调用 HashMap 中的方法。

HashMap HashSet
实现了Map接口 实现Set接口
存储键值对 仅存储对象
调用 put()向map中添加元素 调用 add()方法向Set中添加元素
HashMap使用键(Key)计算Hashcode HashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,

6、HashSet如何检查重复

当你把对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他加入的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同hashcode值的对象,这时会调用equals()方法来检查hashcode相等的对象是否真的相同。如果两者相同,HashSet就不会让加入操作成功。(摘自我的Java启蒙书《Head fist java》第二版)

hashCode()与equals()的相关规定

  1. 如果两个对象相等,则hashcode一定也是相同的
  2. 两个对象相等,对两个equals方法返回true
  3. 两个对象有相同的hashcode值,它们也不一定是相等的
  4. 综上,equals方法被覆盖过,则hashCode方法也必须被覆盖
  5. hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)。

==与equals的区别

  1. ==是判断两个变量或实例是不是指向同一个内存空间 equals是判断两个变量或实例所指向的内存空间的值是不是相同
  2. ==是指对内存地址进行比较 equals()是对字符串的内容进行比较
  3. ==指引用是否相同 equals()指的是值是否相同

7、comparable和comparator的区别

  • comparable接口实际上是java.lang包。它有一个compareTo(Object obj)方法用来排序
  • comparator接口实际上是java.util包它有一个compare(Object obj1, Object obj2)方法用来排序

一般我们需要对一个几个使用自定义排序时,就要重写compare方法或compareTo方法,当我们需要对某一个集合使用两种排序方式。比如一个song对象中的歌手和歌名分别采用一种排序方式的话,我们可以重写compareTo方法和使用自制的Comparator方法或者以两个Comparator来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的Collections.sort().

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

Collection
1.list

  • ArrayList:Object数组
  • Vector:Object数组
  • LinkList:双向列表(JDK1.6之前为链表循环,JDK1.7取消了循环)

2.Set

  • HashSet(无序,唯一):基于HashMap实现的,底层采用HashMap来保存元素
  • LinkHashSet:LinkHashSet继承与HashSet,并且内部是通过LinkHashMap实现的。
  • TreeSet(有序,唯一):红黑树(自平衡的排序二叉树)

Map

  • HashMap:JDK1.8之前HashMap由数组+链表组成,数组是HashMap的主体,链表则是为了解决哈希冲突而存在的。JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8时),将链表转化为红黑树,以减少搜索时间
  • LinkHashMap:LinkHashMap继承自HashMap,所以它的底层任然是基于拉链式散列结构,也就是数组和链表或红黑树组成。另外,LinkHashMap在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表的同时操作,实现了访问顺序相关逻辑。
  • Hashtable: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
  • TreeMap: 红黑树(自平衡的排序二叉树)

9、如何选用集合

主要根据集合的特点来选用,比如我们需要根据键值获取元素值就选用Map接口下的集合,需要排序时选择TreeMap,不需要排序时就现在HashMap,需要保证线程安全时就选用ConcurrentHashMap。当我们只需要存放元素数据时,就选择实现Collection接口的集合,需要保证元素唯一时选择实现Set接口的集合比如TreeSet或HashSet,不需要就选择实现List接口
比如ArrayList或LinkList,然后再根据实现这些接口的集合的特点来选用。

 

 

 
 
 
 
 
 
 
 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章