在 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);}
仔细分析一下:- 当我们要 add 进第 1 个元素到 ArrayList 时,elementData.length 为 0 (因为还是一个空的 list),然后执行了
ensureCapacityInternal()
方法,所以 minCapacity 此时为 10 。此时 ,推荐阅读
- Java单例模式,看这一篇就够了
- 微信支付v3接口的 官方 Java SDK
- Java函数式编程:二、高阶函数,闭包,函数组合以及柯里化
- 夯实Java基础,一篇文章全解析线程问题
- 四 Java多线程-ThreadPool线程池-2
- 生成器函数 javascript异步编程之generator与asnyc/await语法糖
- Java Timer使用介绍
- 三 Java多线程-ThreadPool线程池
- 二 Java多线程-线程关键字
- 二 Java 编码那些事