ArrayList源码分析
一、基本类图
二、List中的方法
1、遍历ArrayList的几种方法
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
//遍历list
//1.迭代器
Object next = null;
// Iterator iterator = list.iterator();
// while (iterator.hasNext()) {
// //next每次会被赋予不同的值
// next = iterator.next();
// //所以要每次输出
// System.out.println(next);
// }
// while(iterator.hasNext()){
// next = iterator.next();
// System.out.println(next);
// }
//2.增强器(底层也是使用迭代器实现)
for(int i : list){
System.out.println(i);
}
迭代器遍历
Iterator iterator = list.iterator();//调用iterator方法(迭代器),返回一个迭代器
while(iterator.hasNext){//迭代器有下一个就进入
//迭代器最开始指向空(数组第一个元素的上一个位置)
//所以指针下移一位后得到数组第的一个元素
Object o = iterator.next();//将遍历到的值赋值给o
System.out.println("o=>"+o);
}
增强for循环
for(Object o : list){//底层同样是迭代器
System.out.println("o=>"+o);
}
普通for循环
for(int i=0; i<list.size(); i++){
System.out.println("o=>"+list.get(i));
}
2、ArrayList中的方法
package com.liu.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import java.util.function.UnaryOperator;
/**
* list方法练习
*/
public class List_ {
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
//size() 数组的大小
System.out.println("size()=>"+list.size());
//add(index)添加 向list的结尾填加元素
list.add("liuzhiyuan");
list.add("hongrundong");
list.add("sujiantao");
list.add("kkk");
System.out.println("list=>"+list);
//add(index,element) 在指定位置添加元素
list.add(1,"kkk");
System.out.println("list=>"+list);
//isEmpty() 判断集合是否为空
System.out.println("isEmpty()=>"+list.isEmpty());
//get(index)获取指定下标的元素
System.out.println("get()=>"+list.get(1));
//listIterator(index)从指定位置开始一直到末尾
ListIterator<Object> lsitIterator = list.listIterator(1);
while (lsitIterator.hasNext()) {
Object next = lsitIterator.next();
System.out.println("listIterator=>"+next);
}
//addAll(Collection) 将一个新的集合添加到原集合后
List list1 = new ArrayList<>();
list1.add("new List");
list.addAll(list1);
System.out.println("addAll()=>"+list);
//clear() 清空所有list中的元素
//list.clear();
//System.out.println("list=>"+list);
System.out.println("equals=>"+list.equals(list1));
//contains(Object) 判断list中是否存在object这个元素
//containsAll(Collection) 判断list是否包含list1中所有元素
System.out.println("contains()=>"+list.contains("kkk"));
System.out.println("containsAll()=>"+list.containsAll(list1));
System.out.println("hashCode()+>"+list.hashCode());
System.out.println("list=>"+list);
//indexOf(Object o) 返回list中object元素所在的第一个位置
System.out.println("indexOf()=>"+list.indexOf("kkk"));
//lastIndexOf(Object o) 返回list中 o所在的最后一个位置
System.out.println("lastIndexOf()=>"+list.lastIndexOf("kkk"));
//remove(Object) 移除指定元素(仅移除第一个)
list.remove("kkk");
System.out.println("list=>"+list);
//remove(index) 移除指定位置元素
list.remove(0);
System.out.println("list=>"+list);
//无法这样移除,因为list中没有list1这个元素
// list.remove(list1);
// System.out.println("list=>"+list);
//removeAll(Collection) 移除所有Collection中含有的元素
//将指定元素在指定位置添加到list中(1为下标,原来的list1长度为1,所以需要在下标为一处添加,
// 也可直接添加( add(object) ),默认加到list1的尾部)
list1.add(1,"test");
list.removeAll(list1);
System.out.println("list=>"+list);
//set(index,object) 更新index位置元素为object
list.set(0,"hhhh");
System.out.println("list=>"+list);
//subList(from,to) 切割原来的list并返回新的list 左闭右开 1 <= x <2
System.out.println("subList=>"+list.subList(1, 2));
//将list转化为数组
System.out.println("toArray()=>"+Arrays.toString(list.toArray()));
}
}
三、ArrayLsit底层源码分析
一、没有初始化list的长度
1、先定义一个ArrayList实现List接口
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
//遍历list
//增强器(底层也是使用迭代器实现)
for(int i : list){
System.out.println(i);
}
2、Debug 进入new ArrayList()
进入debug前先将这条勾选取消,否则我们看不到为空的数据
进入构造函数
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {//帮我们创建一个空数组
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
跳出构造函数
进入Integer装箱
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
跳出Integer
进入add方法
size指的是当前真实list中所含有元素的数量
public boolean add(E e) {
//确认数组容量是否足够
ensureCapacityInternal(size + 1); // Increments modCount!!
//将要添加的值赋值给elementData[size++]
elementData[size++] = e;
return true;
}
进入ensureCapacityInternal方法
//size指的是当前真实list中所含有元素的数量
//minCapacity即为arraylist的size+1
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
calculateCapacity 计算当前数组容量
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10; //ArrayList默认大小
private static int calculateCapacity(Object[] elementData, int minCapacity) {//传入当前数组,及minCapacity(为size+1)
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//若elementData为空
return Math.max(DEFAULT_CAPACITY, minCapacity);//返回DEFAULT_CAPACITY和minCapacity的最大值
}
//若数组不为空,则返回minCapacity
return minCapacity;
}
ensureExplicitCapacity
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //计数*此列表在结构上被修改的次数。结构修改是指改变结构尺寸的修改列表,
//或者以这样一种方式对其进行扰动,使得过程中的迭代可能产生错误的结果。
//minCapacity是calculateCapacity方法计算后返回的容量
//elementData.length即为arraylist底层数组的容量
if (minCapacity - elementData.length > 0) //判断arraylist的之前的size+1后,arrayList底层数组的容量是否够用
grow(minCapacity);
}
grow 扩容核心算法
private void grow(int minCapacity) {
// overflow-conscious code
//记录原数组长度
int oldCapacity = elementData.length;
//原数组长度+原数组长度右移一位(原数组除2,int型除完后向下取整)
//即为扩容为原来的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//若新数组扩容后的长度比minCapacity小
//处理当newCapacity为0的情况,给minCapacity默认赋值为10
if (newCapacity - minCapacity < 0)
//将minCapacity的值赋值给newCapacity
newCapacity = minCapacity;
//newCapacity过大,超过MAX_ARRAY_SIZE时,报错
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//将elementData扩容,并保留原来的元素
elementData = Arrays.copyOf(elementData, newCapacity);
}
跳出grow
跳出ensureExplicitCapacity
跳出ensureCapacityInternal
回到add方法,经e添加到新的elementData中
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
成功添加第一个元素
这时默认将arraylist数组扩容为10
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u21VzNYu-1635388813251)(…/img/arraylist2.jpg)]
后续在数组容量小于等于10时,均不需要扩容
当数量大于10时,才需要再次扩容为原来的1.5倍
二、初始化了list的长度
List<Integer> list = new ArrayList<Integer>(3);
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
//遍历list
for(int i=0; i<list.size(); i++){
System.out.println("o=>"+list.get(i));
}
大体上基本一样
仅在构造函数时有所差别
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
四、总结(重点)
ArrayList 在未初始化长度的情况下,第一次将数组扩容为10
在初始化长度的情况下,则长度为初始化的长度
若数组长度不足,则扩容为原来的1.5倍(注意:扩容机制为int型,所以向下取整,15扩容为15+15/2=22)