JDK源码学习系列04----ArrayList
来源:互联网 发布:在线兼职美工 编辑:程序博客网 时间:2024/06/05 14:06
JDK源码学习系列04----ArrayList
1.ArrayList简介
ArrayList是基于Object[] 数组的,也就是我们常说的动态数组。它能很方便的实现数组的增加删除等操作。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable</span>
ArrayList支持泛型,它继承自AbstractList,实现了List、RandomAccess、Cloneable、java.io.Serializable接口。
List接口定义了列表必须实现的方法。
RandomAccess是一个标记接口,接口内没有定义任何内容。
实现了Cloneable接口的类,可以调用Object.clone方法返回该对象的浅拷贝。
通过实现 java.io.Serializable 接口以实现序列化功能。
private transient Object[] elementData;//注意关键字 transientprivate int size;//实际size,不是容量Java关键字 transient:是为了在序列化时保护对象的某些域不被序列化,在Java序列化Serializable详解中有所提及。关于transient的详细内容稍后补上。
3.ArrayList构造函数
public ArrayList(int initialCapacity) {//为ArrayList初始化容量super(); if (initialCapacity < 0)//若传入参数小于0,则报IllegalArgumentException的错误 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);this.elementData = new Object[initialCapacity];//初始elementData数组的大小为此传入的参数 } public ArrayList() {//ArrayList初始容量,即默认容量为10this(10); } public ArrayList(Collection<? extends E> c) {//把整个集合初始化给ArrayList.注意:该集合内的数据类型必须与ArrayList一致!!!!elementData = c.toArray();size = elementData.length;// c.toArray might (incorrectly) not return Object[] (see 6260652)//!!这是jdk的一个bug,说是c.toArray()不一定返回的是Object类型if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class);//调用的Arrays.copyOf() }4.ArrayList的成员函数
a.void trimToSize()
public void trimToSize() {//节约内存modCount++;//此变量记录ArrayList被改变的次数 !!!超级注意!!!int oldCapacity = elementData.length;if (size < oldCapacity) {//!!size往往不等于elementData.length;elementData.length是数组的初始长度,size是实际内容的长度!! elementData = Arrays.copyOf(elementData, size);} }modCount变量是记录ArrayList被改变的次数。为什么需要这个变量呢?
ArrayList不是线程安全(异步)的。这里会引出Fail-Fast机制:
ArrayList不是线程安全的,因此如果在使用迭代器的过程中有其他线程修改了map,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。
这一策略在源码中的实现是通过modCount域,modCount顾名思义就是修改次数,对ArrayList 结构的修改(长度的变化,增加,删除;赋值不是结构变化)都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的expectedModCount。在迭代过程中,判断modCount跟expectedModCount是否相等,如果不相等就表示已经有其他线程修改了ArrayList。
ArrayList中的mouCount是在他的父类Abstract中申明的。
protected transient int modCount = 0;b.void ensureCapacity(int minCapacity)
public void ensureCapacity(int minCapacity) {modCount++;int oldCapacity = elementData.length;if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1;//若传入参数大于原容量,先扩为 1.5*原容量+1 if (newCapacity < minCapacity)newCapacity = minCapacity;//若扩为 1.5*原容量+1 后还是小于传入的参数,则把传入的参数作为新容量 // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity);} }ArrayList需要扩容时至少都是扩为 1.5*原容量+1 ,若1.5*原容量+1 还是小于传入的参数,才把传入的参数作为新容量。
c.boolean contains(Object o)
public boolean contains(Object o) {return indexOf(o) >= 0; }d.int indexOf(Object o)
public int indexOf(Object o) {if (o == null) {//定位是null也要定位的哦~ for (int i = 0; i < size; i++)if (elementData[i]==null) return i;} else { for (int i = 0; i < size; i++)if (o.equals(elementData[i])) return i;}return -1; }e.Object[] toArray() / <T> T[] toArray(T[] a)
调用的是Arrays.copyOf()
public Object[] toArray() { return Arrays.copyOf(elementData, size); }
public <T> T[] toArray(T[] a) { if (a.length < size) // Make a new array of a's runtime type, but my contents: return (T[]) Arrays.copyOf(elementData, size, a.getClass());//若传入的数组长度小于size(ArrayList实际长度),则返回一个长度为size新的数组System.arraycopy(elementData, 0, a, 0, size);//若传入数组长度相等,则把elementData复制进传入数组 if (a.length > size)//若传入的a的长度大于原本数组,则后面补null a[size] = null; return a; }f.E set(int index, E element)
set是直接替换掉该位置元素;而add是插入该位置,其余元素后移。
public E set(int index, E element) {RangeCheck(index);//参数检查的方法~~一定要时刻注意参数检查哦~~E oldValue = (E) elementData[index];elementData[index] = element;return oldValue; }g.boolean add(E e) / void add(int index, E element)
public boolean add(E e) {ensureCapacity(size + 1); // add()时先扩容!elementData[size++] = e;//!!写的很好,size++的同时还完成了在最后位置的赋值。之所以size++不会报边界溢出的错误是因为上面已经扩容了。return true; }
public void add(int index, E element) {if (index > size || index < 0)throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);ensureCapacity(size+1); // Increments modCount!!System.arraycopy(elementData, index, elementData, index + 1,size - index);//!!把elementData的数据从index->末尾全部复制到从index+1开始,复制长度无size-indexelementData[index] = element;//相当于把传入的element插入到空出的位置,即原indexsize++; }注意System.arracopy()方法!!
h.E remove(int index) / boolean remove(Object o) / void fastRemove(int index)
public E remove(int index) {RangeCheck(index);modCount++;E oldValue = (E) elementData[index];//得到需要返回的被remove掉的元素int numMoved = size - index - 1;//复制时复制的长度,if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index,numMoved);//把原数组从index+1-->末尾的数据复制到 index的位置,即相当于把原本index上的数据覆盖掉了,这样最后就空出了一个位置。elementData[--size] = null; // 先把size减一,在把最后一赋值为nullreturn oldValue; }
public boolean remove(Object o) {if (o == null) {//!!判断是否为null ,养成编程好习惯 for (int index = 0; index < size; index++)if (elementData[index] == null) { fastRemove(index);//这肯定是在边界之类,所以可以快速移除 return true;}} else { for (int index = 0; index < size; index++)if (o.equals(elementData[index])) { fastRemove(index); return true;} }return false; }
private void fastRemove(int index) {//快速移除! 此方法跳过了边界检查这一步,且不会返回被移除的元素。平时还是不要用哦~~ modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index,numMoved); elementData[--size] = null; // Let gc do its work }i.void clear()
public void clear() {//把每个都置为null,再设置size=0;modCount++;// Let gc do its workfor (int i = 0; i < size; i++) elementData[i] = null;size = 0; }g.boolean addAll(int index, Collection<? extends E> c)
public boolean addAll(int index, Collection<? extends E> c) {if (index > size || index < 0) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);Object[] a = c.toArray();int numNew = a.length;ensureCapacity(size + numNew); // 扩容时传入的参数为:现在的实际长度+传入的集合的长度int numMoved = size - index;if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew,numMoved);//把原数组从index-->末尾复制到 index+numNew-->末尾,即中间空出numNum的长度来为传入的集合做准备。 System.arraycopy(a, 0, elementData, index, numNew);size += numNew;return numNew != 0; }5.总结
a.ArrayList动态数组!
b.ArrayList 非线程安全,即 是异步的。 单线程才用ArrayList。
- JDK源码学习系列04----ArrayList
- JDK源码学习之ArrayList
- jdk源码学习笔记---ArrayList
- 【JDK源码】从JDK/ArrayList源码学习高质量代码
- JDK源码学习之Arraylist与LinkedList
- JDK源码-ArrayList源码
- JDK ArrayList 删除源码
- ## JDK源码--ArrayList
- JDK源码阅读-ArrayList
- jdk源码分析--ArrayList
- [Java]JDK源码学习(1)ArrayList和Vector
- 通过ArrayList迭代器使用进行JDK源码分析学习迭代器
- java核心基础--jdk源码分析学习--ArrayList
- 【JDK源码】JDK/ArrayList源码逐行详解
- JDK源码学习系列01----String
- JDK源码学习系列02----AbstractStringBuilder
- JDK源码学习系列03----StringBuffer+StringBuilder
- JDK源码学习系列05----LinkedList
- 指针和引用的差别
- Spring AOP技术--动态代理
- jar读取内部文件
- GDI+ 学习笔记(一)概述
- 自编码器及相关变种算法简介
- JDK源码学习系列04----ArrayList
- D算法图解
- NSString与int和float的相互转换
- resin和eclipse整合(傻瓜式)
- openfire_服务器部署到centos上
- Windows内核之线程的调度,优先级,亲缘性
- hdu 2196 树形dp
- 关于黑帽SEO的16种常见操作手法解析
- PostgreSql中的timestamp用法