Java集合精选常见面试题( 三 )


binarySearch() 方法中,它要判断传入的 list 是否 RamdomAccess 的实例,如果是,调用indexedBinarySearch()方法,如果不是,那么调用iteratorBinarySearch()方法
public static <T>int binarySearch(List<? extends Comparable<? super T>> list ,  T key) {if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)return Collections.indexedBinarySearch(list,key);elsereturn Collections.iteratorBinarySearch(list,key);}ArrayList 实现了 RandomAccess 接口 ,  而 LinkedList 没有实现 。为什么呢?我觉得还是和底层数据结构有关!ArrayList 底层是数组,而 LinkedList 底层是链表 。数组天然支持随机访问,时间复杂度为 O(1) , 所以称为快速随机访问 。链表需要遍历到特定位置才能访问特定位置的元素,时间复杂度为 O(n),所以不支持快速随机访问 。,ArrayList 实现了 RandomAccess 接口,就表明了他具有快速随机访问功能 。RandomAccess 接口只是标识,并不是说 ArrayList 实现 RandomAccess 接口才具有快速随机访问功能的
3. 说一说 ArrayList 的扩容机制吧ArrayList核心源码详见这篇文章:通过源码一步一步分析 ArrayList 扩容机制
先从 ArrayList 的构造函数说起(JDK8)ArrayList 有三种方式来初始化,构造方法源码如下:
/*** 默认初始容量大小10*/private static final int DEFAULT_CAPACITY = 10;private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = https://www.huyubaike.com/biancheng/{};/***默认构造函数,使用初始容量10构造一个空列表(无参数构造)*/public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}/*** 带初始容量参数的构造函数 。(用户自己指定容量)*/public ArrayList(int initialCapacity) {if (initialCapacity > 0) {//初始容量大于0//创建initialCapacity大小的数组this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {//初始容量等于0//创建空数组this.elementData = EMPTY_ELEMENTDATA;} else {//初始容量小于0,抛出异常throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}/***构造包含指定collection元素的列表,这些元素利用该集合的迭代器按顺序返回*如果指定的集合为null,throws NullPointerException 。*/public ArrayList(Collection<? extends E> c) {elementData = https://www.huyubaike.com/biancheng/c.toArray();if ((size = elementData.length) != 0) {// c.toArray might (incorrectly) not return Object[] (see 6260652)if (elementData.getClass() != Object[].class)elementData = Arrays.copyOf(elementData,size,Object[].class);} else {// replace with empty array.this.elementData = EMPTY_ELEMENTDATA;}}细心的同学一定会发现 :以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组 。当真正对数组进行添加元素操作时,才真正分配容量 。即向数组中添加第一个元素时,数组容量扩为 10 。下面在我们分析 ArrayList 扩容时会讲到这一点内容!

补充:JDK6 new 无参构造的 ArrayList 对象时,直接创建了长度是 10 的 Object[] 数组 elementData
add()
/*** 将指定的元素追加到此列表的末尾 。*/public boolean add(E e) {//添加元素之前,先调用ensureCapacityInternal方法ensureCapacityInternal(size + 1);// Increments modCount!!//这里看到ArrayList添加元素的实质就相当于为数组赋值elementData[size++] = e;return true;}ensureCapacityInternal()
(JDK7)可以看到 add 方法 首先调用了ensureCapacityInternal(size + 1)
//得到最小扩容量private void ensureCapacityInternal(int minCapacity) {if (elementData =https://www.huyubaike.com/biancheng/= DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {// 获取默认的容量和传入参数的较大值minCapacity = Math.max(DEFAULT_CAPACITY , minCapacity);}ensureExplicitCapacity(minCapacity);}如果调用 ensureCapacityInternal() 方法就一定会进入(执行)这个方法 , 下面我们来研究一下这个方法的源码!
//判断是否需要扩容private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)//调用grow方法进行扩容,调用此方法代表已经开始扩容了grow(minCapacity);}仔细分析一下: