List源码解析
开始看一下集合Collection,List是Collection的一个子接口,其是很常用的,主要是看一下其下的几个类。
1、AbstractList
2、ArrayList
3、Collections.synchronizedList
4、Vector
5、LinkedList
6、CopyOnWriteArrayList
一、AbstractList
这是一个抽象类,其是实现List接口基础类,像ArrayList、LinkedList和Vector都是继承此抽象类的。
1》如果要实现一个不可变的列表,必须实现get(int) 和size()方法
2》如果要实现一个可修改的列表,必须实现set(int,E),如果列表大小可变,必须另外实现add(int,E)和remove(int)方法
其内置了两个迭代器,是Itr和ListItr,继承关系如下
(1)Itr
private class Itr implements Iterator<E> {
//游标
int cursor = 0;
//调用next方法时当前的下标索引值
//,如果调用了remove方法,则重置为-1
int lastRet = -1;
//列表被修改的次数,比如增、删、改、扩容等操作
int expectedModCount = modCount;
//是否还有元素
public boolean hasNext() {
return cursor != size();
}
//返回下一个元素
public E next() {
checkForComodification();
try {
int i = cursor;
//get方法是调用具体实现类的
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
//删除当前元素
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
//检查迭代的时候列表结构是否有被其他线程修改过
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
(2)ListItr
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
//返回前一个元素
public E previous() {
checkForComodification();
try {
int i = cursor - 1;
E previous = get(i);
lastRet = cursor = i;
return previous;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor-1;
}
//设值
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.set(lastRet, e);
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
//添加元素
public void add(E e) {
checkForComodification();
try {
int i = cursor;
AbstractList.this.add(i, e);
lastRet = -1;
cursor = i + 1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
这两个迭代器在indexOf、lastIndexOf和removeRange方法中有调用
例如removeRange方法
protected void removeRange(int fromIndex, int toIndex) {
//获取迭代器,fromIndex就是Itr里面的cursor
ListIterator<E> it = listIterator(fromIndex);
for (int i=0, n=toIndex-fromIndex; i<n; i++) {
it.next();
it.remove();
}
}
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
cursor = index;
}
}
二、ArrayList
这个列表是最常用的,继承自AbstractList,非线程安全,多线程下会抛出ConcurrentModificationException
(1)默认容量是10
private static final int DEFAULT_CAPACITY = 10;
(2)底层数据结构是一个Object数组
transient Object[] elementData;
(3)扩容机制为扩容为当前容量的1.5倍,看add方法
public boolean add(E e) {
//关键就是方法
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
扩容看ensureCapacityInternal方法
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(
calculateCapacity(elementData, minCapacity)
);
}
先看calculateCapacity方法
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
如果创建列表时没有指定大小,就从minCapacity和默认容量两个数中取最大。否则直接返回minCapacity
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//如果minCapacity大于当前数组长度,则进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
扩容最核心的方法是grow(minCapacity)方法。
private void grow(int minCapacity) {
//当前容量
int oldCapacity = elementData.length;
//新容量,是当前容量的1.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);
}
可以看到,扩容后容量为当前容量的1.5倍
三、Collections.synchronizedList
用Collections获取的这个List是线程安全的,其都是用synchronized关键字在代码块上进行加锁的。具体初始容量以及扩容看传入的是哪种List
返回的list是SynchronizedRandomAccessList或者是SynchronizedList,而SynchronizedRandomAccessList又是SynchronizedList的子类
所以主要看SynchronizedList,可以看到,这个类的所有方法都是用Synchronized加锁的。
四、Vector
Vector比较少用,其也是AbstractList的子类。
(1)默认容量,也是10
public Vector() {
//调用另外一个构造方法
this(10);
}
上述默认空构造调用下面这个构造方法,其将capacityIncrement设为0,这个在扩容时有用
也可以用下面这个构造初始化容量和capacityIncrement
(2)底层数据结构是一个Object数组
protected Object[] elementData;
(3)扩容机制默认是2倍,也可以手动设置capacityIncrement扩容
(4)线程安全,用Synchronized在方法上加锁
五、LinkedList
这个链表结构如下,除了继承了AbstractList,还实现了Queue。
(1)底层实现是一个一个Node节点,节点中存有前后节点的引用,能连成一条链
六、CopyOnWriteArrayList
这个就比较牛逼了,中文名叫写时复制。属于JUC并发包里面的,线程安全,是ArrayList的变体。
(1)初始化是容量为0的Object数组
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
这个数组是用volatile,保证变量内存可见性。
private transient volatile Object[] array;
(2)用ReentrantLock(递归锁,又称可重入锁)加锁,扩容为添加一次就容量加1,然后用Arrays.copyOf将旧的数组复制到新数组内,比较耗内存。
- 细说log4j
- SEVERE: Error configuring application listener of class org.springframework.web.context.ContextLoade
- TCP/IP(一)之开启计算机网络之路
- JSON入门指南--客户端处理JSON
- mysql5.7 ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
- TCP/IP中你不得不知的十大秘密
- Java Web开发学习之路2012版
- TortoiseSVN客户端使用的2个配置问题
- JavaWeb(二)会话管理之细说cookie与session
- 概率论09 期望
- Javascript中数组的sort()和reverse()方法
- CentOS6.5开放端口,配置防火墙
- JavaWeb(一)Servlet中乱码解决与转发和重定向的区别
- Java魔法堂:四种引用类型、ReferenceQueue和WeakHashMap
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- JavaWeb——AJAX异步技术实现方式与案例实战(原生的JS方式、使用JQuery方式)
- JavaWeb——一文带你入门Servlet(生命周期、注解配置方法、IDEA与tomcat的相关配置)
- JavaWeb——JQuery之基础案例实战(实现表格隔行换色、实现全选全不选、QQ表情选择、下拉列表选中条目左右选择功能)
- JavaWeb——JQuery之DOM操作应用及实践案例总结(DOM内容操作、DOM属性操作、CRUD操作)
- JavaWeb——Filter过滤器快速入门与是否登录验证&过滤敏感词汇案例实战(Filter配置方式、执行流程、生命周期方法、过滤器链)
- JavaWeb——会话技术之Session快速入门与验证码登录案例实战(Session实现原理、使用细节、快速入门、Session的特点)
- Nginx配置文件服务器
- JavaWeb——会话技术之Cookie快速入门与案例实战(详细讲解了Cookie实现原理、Cookie使用细节、Cookie的特点及作用)
- docker安装kibana
- JavaWeb——ServletContext对象的使用及文件下载案例实战
- (最新 9000 字 )Spring Boot 配置特性解析
- JavaWeb——HTTP响应协议及Response对象使用方法一点通及案例实战(重定向、输出字符/字节数据到浏览器、验证码实现)
- drf序列化器之反序列化的数据验证
- yum仅下载不安装---保留rpm包
- Java——数据库编程JDBC之JDBCTemplate的使用简化数据库操作步骤(含增删改查练习实例源码)