ArrayList源码阅读笔记
ArrayList
ArrayList继承自AbstractList抽象类,实现了RandomAccess, Cloneable, java.io.Serializable接口,其中RandomAccess是一个标志接口,代表可以支持快速随机访问,实现该接口的类使用for循环比使用迭代器要快,LinkedList并未实现该接口,它用迭代器进行遍历要比ArrayList用迭代器要快。可以用instanceof确定某obj是否实现RandomAccess。Cloneable:标志接口,表示可被克隆;java.io.Serializable可序列化标志接口。(克隆和序列化还能继续研究 。。。)
ArrayList是动态的、长度可变的,但底层由长度不可变的数组实现,默认数组大小为10,可以用ArrayList(int lenth)初始化数组长度,也可以使用ensureCapacity(int minCapacity)来预估数据数量而提前扩容(用此方法扩容时ArrayList不能为空数组)。
在进行扩容时多次使用Arrays.copyOf(obj [],newObj [])方法,扩容大小由内部方法newCapacity(int minCapacity)确定:
/**
* Returns a capacity at least as large as the given minimum capacity.返回至少与给定最小容量相同的容量
* Returns the current capacity increased by 50% if that suffices.如果满足,则返回当前容量增加50%
* Will not return a capacity greater than MAX_ARRAY_SIZE unless
* the given minimum capacity is greater than MAX_ARRAY_SIZE.
*除非给定的最小容量大于MAX_ARRAY_SIZE,否则不会返回大于MAX_ARRAY_SIZE的容量。
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;//原长度
int newCapacity = oldCapacity + (oldCapacity >> 1);//原长度1.5倍
if (newCapacity - minCapacity <= 0) {//如果给定长度大于1.5倍
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);//为空则返回给定和默认中大的
if (minCapacity < 0) // overflow不能给负数
throw new OutOfMemoryError();
return minCapacity;//否则就返回给定值
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);//这里,MAX_ARRAY_SIZE为Integer.MAX_VALUE-8,因为部分虚拟机会存储head code(头部信息?),所以直接给Integer.MAX_VALUE会报错:数组大小超出VM限制。但它还是会把这8个位置给你233333
}
说完扩容,说缩容,正常情况下开辟过的容量并不会减少,不使用了会赋null(比如clear()方法,以及内部的protected void removeRange()),但这样会造成浪费,因此可以使用trimToSize()方法把其中的数组大小修改为元素数量(trim:修剪)。
其中add、remove方法使用System.arraycopy(Object src, int srcPos,Object dest, int destPos,int length)来创建新的数组,从而表现出长度可变的特性。//这么做代表数组中间不会有null值,但是数组尾部未使用的会有null值。
removeAll(c),可以删除和c相同的元素,也就是求与c的差集;
retainAll(c),可以保留和c相同的元素,也就是求与c的交集。这两个方法都调用了期内部方法`batchRemove方法:
boolean batchRemove(Collection<?> c, boolean complement,
final int from, final int end) {
Objects.requireNonNull(c);//c中不能有null
final Object[] es = elementData;//获取原数组
int r;//声明遍历标志位
// Optimize for initial run of survivors
//优化幸存者的初始运行,也就是处理需要保留的元素
for (r = from;; r++) {
if (r == end)//removeAll与retainAll方法调用时传参from为0,end为数组大小size,这里判断是否需要执行删除操作
return false;//false代表没有元素删除
if (c.contains(es[r]) != complement)
break;//代表需要删除元素
}
int w = r++;//声明保留标志位,初始化为第一个要删除的元素,同时r+1继续遍历
try {
for (Object e; r < end; r++)
if (c.contains(e = es[r]) == complement)
es[w++] = e;//这里执行的不是删除,而是将后面需要保留的元素覆盖掉第一个需要删除的元素,相当于把需要保留的元素向前移动了
} catch (Throwable ex) {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
//保留与AbstractCollection的行为兼容性,即使c.contains()抛出也是如此。
System.arraycopy(es, r, es, w, end - r);
w += end - r;
throw ex;
} finally {
modCount += end - w;//修改(删除)的次数
shiftTailOverGap(es, w, end);//拷贝需要保留的元素,同时将后面移动过后的元素赋null
}
return true;//代表修改(删除)了元素
}
该方法还是比较精妙的。
至于迭代器了,恕笔者学识尚浅,就不发表拙见了//待更新。。。
疑点:其中两个私有的io方法,这俩玩意有什么用?私有不说,光见它声明没见它调用啊//待更新。。。
/**
* Saves the state of the {@code ArrayList} instance to a stream
* (that is, serializes it).
*
* @param s the stream
* @throws java.io.IOException if an I/O error occurs
* @serialData The length of the array backing the {@code ArrayList}
* instance is emitted (int), followed by all of its elements
* (each an {@code Object}) in the proper order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioral compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
/**
* Reconstitutes the {@code ArrayList} instance from a stream (that is,
* deserializes it).
* @param s the stream
* @throws ClassNotFoundException if the class of a serialized object
* could not be found
* @throws java.io.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// like clone(), allocate array based upon size not capacity
SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size);
Object[] elements = new Object[size];
// Read in all elements in the proper order.
for (int i = 0; i < size; i++) {
elements[i] = s.readObject();
}
elementData = elements;
} else if (size == 0) {
elementData = EMPTY_ELEMENTDATA;
} else {
throw new java.io.InvalidObjectException("Invalid size: " + size);
}
}
ArrayList源码阅读笔记的更多相关文章
- ArrayList源码阅读笔记(1.8)
目录 ArrayList类的注解阅读 ArrayList类的定义 属性的定义 ArrayList构造器 核心方法 普通方法 迭代器(iterator&ListIterator)实现 最后声明 ...
- ArrayList源码阅读笔记(基于JDk1.8)
关键常量: private static final int DEFAULT_CAPACITY = 10; 当没有其他参数影响数组大小时的默认数组大小 private static final Obj ...
- jdk源码阅读笔记-LinkedHashMap
Map是Java collection framework 中重要的组成部分,特别是HashMap是在我们在日常的开发的过程中使用的最多的一个集合.但是遗憾的是,存放在HashMap中元素都是无序的, ...
- CopyOnWriteArrayList源码阅读笔记
简介 ArrayList是开发中使用比较多的集合,它不是线程安全的,CopyOnWriteArrayList就是线程安全版本的ArrayList.CopyOnWriteArrayList同样是通过数组 ...
- Mina源码阅读笔记(四)—Mina的连接IoConnector2
接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...
- HashMap源码阅读笔记
HashMap源码阅读笔记 本文在此博客的内容上进行了部分修改,旨在加深笔者对HashMap的理解,暂不讨论红黑树相关逻辑 概述 HashMap作为经常使用到的类,大多时候都是只知道大概原理,比如 ...
- java8 ArrayList源码阅读
转载自 java8 ArrayList源码阅读 本文基于jdk1.8 JavaCollection库中有三类:List,Queue,Set 其中List,有三个子实现类:ArrayList,Vecto ...
- CI框架源码阅读笔记5 基准测试 BenchMark.php
上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...
- CI框架源码阅读笔记4 引导文件CodeIgniter.php
到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...
随机推荐
- InnoDB 和 MyISAM的索引区别
MyISAM索引实现 MyISAM索引文件和数据文件是分离的,索引文件的data域保存记录所在页的地址(物理存储位置),通过这些地址来读取页,进而读取被索引的行数据. MyISAM的索引原理图如下,C ...
- html5,css3炫酷实例-元素
自动完成输入框下拉列表 使用的插件:jquery-ui 使用数据源实现文本框的自动完成功能 <link href="https://cdn.bootcss.com/jqueryui/1 ...
- 7.6 CLI 管理Varnish
./varnishd -f /usr/common/varnish/etc/varnish/ -a 测试: 代理tomcat服务器地址:http://172.20.10.5:1111/ telnet ...
- 5 GC 参数
- 微信扫码登陆(JAVA)
在web端用到weChat扫码登录,在手机扫码登陆成功后,跳转到相应的界面. 1.第一步请求code 调用接口:https://open.weixin.qq.com/connect/qrconnect ...
- 吴裕雄--天生自然java开发常用类库学习笔记:Map接口
import java.util.HashMap ; import java.util.Map ; public class HashMapDemo01{ public static void mai ...
- jmeter简单压测、下载文件
一.jmeter做简单压测(单机) 1.添加需要压测的HTTP请求 2.添加聚合报告 3.设置压测场景 4.查看聚合报告 二.多机同时进行压测 1.在需要连接的电脑上打开jmeter bin目录下的 ...
- python 安装opendr 报错OSMesa
### 报错/ERROR: ```opendr/contexts/OSMesa/include/GL/glext.h:5794:21: note: expected ‘const GLchar ** ...
- C++面试常见问题——09static关键字
static关键字 局部变量 局部变量 局部变量是最常见的量,编译器不会对其进行初始化,除非对其显式赋值,不然初始值是随机的. 普通局部变量存储在栈空间,使用完毕后会立即被释放. 静态局部变量 静态局 ...
- arduino中的serial .available()和serial.read()
Serial.available() 的意思是:返回串口缓冲区中当前剩余的字符个数.一般用这个函数来判断串口的缓冲区有无数据,当Serial.available()>0时,说明串口接收到了数据, ...