文章收录在 GitHub JavaKeeper ,N线互联网开发必备技能兵器谱
作为一位小菜 ”一面面试官“,面试过程中,我肯定会问 Java 集合的内容,同时作为求职者,也肯定会被问到集合,所以整理下 Java 集合面试题
说说常见的集合有哪些吧?
HashMap说一下,其中的Key需要重写hashCode()和equals()吗?
HashMap中key和value可以为null吗?允许几个为null呀?
HashMap线程安全吗?ConcurrentHashMap和hashTable有什么区别?
List和Set说一下,现在有一个ArrayList,对其中的所有元素按照某一属性大小排序,应该怎么做?
ArrayList 和 Vector 的区别
list 可以删除吗,遍历的时候可以删除吗,为什么
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,需要将对象进行存储,集合就是存储对象最常用的一种方式,也叫容器。
从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器
一种是集合(Collection),存储一个元素集合
另一种是图(Map),存储键/值对映射。
Collection 接口又有 3 种子类型,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等等。
集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内容:
接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象
实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。
算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。
说说常用的集合有哪些吧?Map 接口和 Collection 接口是所有集合框架的父接口:
Collection接口的子接口包括:Set、List、Queue
List是有序的允许有重复元素的Collection,实现类主要有:ArrayList、LinkedList、Stack以及Vector等
Set是一种不包含重复元素且无序的Collection,实现类主要有:HashSet、TreeSet、LinkedHashSet等
Map没有继承Collection接口,Map提供key到value的映射。实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap 以及 Properties 等
ArrayList 和 Vector 的区别相同点:
ArrayList 和 Vector 都是继承了相同的父类和实现了相同的接口(都实现了List,有序、允许重复和null)
extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
底层都是数组(Object[])实现的
初始默认长度都为10
不同点:
同步性:Vector 中的 public 方法多数添加了 synchronized 关键字、以确保方法同步、也即是 Vector 线程安全、ArrayList 线程不安全
性能:Vector 存在 synchronized 的锁等待情况、需要等待释放锁这个过程、所以性能相对较差
扩容大小:ArrayList在底层数组不够用时在原来的基础上扩展 0.5 倍,Vector默认是扩展 1 倍
扩容机制,扩容方法其实就是新创建一个数组,然后将旧数组的元素都复制到新数组里面。其底层的扩容方法都在 grow() 中(基于JDK8)
ArrayList 的 grow(),在满足扩容条件时、ArrayList以1.5 倍的方式在扩容(oldCapacity >> 1 ,右移运算,相当于除以 2,结果为二分之一的 oldCapacity)
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //newCapacity = oldCapacity + O.5*oldCapacity,此处扩容0.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }
Vector 的 grow(),Vector 比 ArrayList多一个属性,扩展因子capacityIncrement,可以扩容大小。当扩容容量增量大于0时、新数组长度为原数组长度+扩容容量增量、否则新数组长度为原数组长度的2倍
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; // int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); } ArrayList 与 LinkedList 区别是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
底层数据结构: Arraylist 底层使用的是 Object 数组;LinkedList 底层使用的是双向循环链表数据结构;
插入和删除是否受元素位置的影响: