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源码阅读笔记的更多相关文章

  1. ArrayList源码阅读笔记(1.8)

    目录 ArrayList类的注解阅读 ArrayList类的定义 属性的定义 ArrayList构造器 核心方法 普通方法 迭代器(iterator&ListIterator)实现 最后声明 ...

  2. ArrayList源码阅读笔记(基于JDk1.8)

    关键常量: private static final int DEFAULT_CAPACITY = 10; 当没有其他参数影响数组大小时的默认数组大小 private static final Obj ...

  3. jdk源码阅读笔记-LinkedHashMap

    Map是Java collection framework 中重要的组成部分,特别是HashMap是在我们在日常的开发的过程中使用的最多的一个集合.但是遗憾的是,存放在HashMap中元素都是无序的, ...

  4. CopyOnWriteArrayList源码阅读笔记

    简介 ArrayList是开发中使用比较多的集合,它不是线程安全的,CopyOnWriteArrayList就是线程安全版本的ArrayList.CopyOnWriteArrayList同样是通过数组 ...

  5. Mina源码阅读笔记(四)—Mina的连接IoConnector2

    接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...

  6. HashMap源码阅读笔记

    HashMap源码阅读笔记 本文在此博客的内容上进行了部分修改,旨在加深笔者对HashMap的理解,暂不讨论红黑树相关逻辑 概述   HashMap作为经常使用到的类,大多时候都是只知道大概原理,比如 ...

  7. java8 ArrayList源码阅读

    转载自 java8 ArrayList源码阅读 本文基于jdk1.8 JavaCollection库中有三类:List,Queue,Set 其中List,有三个子实现类:ArrayList,Vecto ...

  8. CI框架源码阅读笔记5 基准测试 BenchMark.php

    上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...

  9. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...

随机推荐

  1. 前端学习(20)~css布局(十三)

    常见的布局属性 (1)display 确定元素的显示类型: block:块级元素. inline:行内元素. inline-block:对外的表现是行内元素(不会独占一行),对内的表现是块级元素(可以 ...

  2. Python测试进阶——(7)动手编写Bash脚本启动Python监控程序并传递PID

    如下: #./cf_workload_functions.sh function timestamp(){ # get current timestamp sec=`date +%s` nanosec ...

  3. JS - 判断字符串某个下标的值

    <html><body> <script type="text/javascript"> var str="0123456789!&q ...

  4. Linux分发版本的试用及选择工具

    https://www.forbes.com/sites/jasonevangelho/2019/06/15/how-to-test-drive-200-linux-distributions-wit ...

  5. 02.swoole学习笔记--UDP服务器

    <?php //创建服务器 $serv=,SWOOLE_PROCESS,SWOOLE_SOCK_UDP); //bool $swoole_server->on(string $event, ...

  6. python3.7的一些心得,不定期更新。

    学习的python3.7.2,最新目前是3.8.1 这里记一下主要的几点: pip 是python的模块管理器,姑且这么叫它.和nodejs的npm一样的功能 官网下载python安装包,默认就会按照 ...

  7. 《新标准C++程序设计》4.6(C++学习笔记16)

    重载流插入运算符和流提取运算符 流插入运算符:“<<” 流提取运算符:“>>” cout 是在 iostream 中定义的,ostream 类的对象. “<<” 能 ...

  8. ubuntu18.04.2 Hadoop伪集群搭建

    准备工作: 若没有下载vim请下载vim 若出现 Could not get lock /var/lib/dpkg/lock 问题请参考: https://jingyan.baidu.com/arti ...

  9. Linux: 桥接 NET HOST-only

    桥接 虚拟机会利用真实的网卡和真实计算机之间通信  还能和同一局域网之间的计算机之间通信 缺点:会耗费一个ip地址 NET:虚拟机会通过VMnet8 虚拟的网卡与真实计算机之间通信    如果真实计可 ...

  10. use matplotlib to draw scatter plot

    There are many pionts in this kind of table. How to do it? We can use scatter() to draw it. Code: im ...