一.ArrayList的构造器和构造方法

  在ArrayList中定义了两个空数组,分别对应当指定默认构造方法时候,指向的数组已经给定容量,但是容量等于0的时候,指向的数组.此外在构造函数中传入Collection对象的时候,直接调用对象的toArray方法,并且将容器内部的引用指向得到的数组.源代码如下:

private static final long serialVersionUID = 8683452581122892189L;

    /**
* 默认的数组的容量
*/
private static final int DEFAULT_CAPACITY = 10; /**
* 在默认构造函数中给定的空对象数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {}; /**
在有参数的构造函数中,如果参数为0,使用这个空对象数组
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /**
装元素的数组
*/
transient Object[] elementData; // non-private to simplify nested class access /**
* 容器大小
*
* @serial
*/
private int size; /**
*如果指定容量>0.new一个object数组
如果==0.使用指定容量为0的引用指向
*/
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);
}
} public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
} public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
//toArray方法可能不会返回Object数组
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 将引用指向空数组.
this.elementData = EMPTY_ELEMENTDATA;
}
}

二.动态调整大小(trimToSize方法)

  该方法使得容器内部的数组的长度和其储存元素的数目相同,通过调用Arrays.copyOf方法(在ArrayList的实现中大量用到了这个方法),完成了将容器内部的引用变量指向一个新的长度为容器中元素的个数的数组.

public void trimToSize() {
modCount++;//属于对容器的容量进行修改的操作,modCount+1
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}

三.ensureCapacity方法

  这个方法增加 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数。需要注意的是,当数组引用指向默认构造函数的空数组的时候,将会判断是否需要增加的容量<10,如果小于10,则直接增加数组的长度至10.当数组的长度不足以容纳元素的时候,会直接将数组的长度变为原来的1.5倍.代码如下:

public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
//如果不是默认的构造函数,下限为0
? 0
// 如果是默认的构造函数.那么下限为10
// 在给定的容量小于10的情况下,不需要扩容
: DEFAULT_CAPACITY; if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
} private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
} private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
} private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)//旧容量的1.5倍<mincapacity的时候,才使用mincapacity
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//elementData指向一个copy好的数组
elementData = Arrays.copyOf(elementData, newCapacity);
} private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}

四.indexOf方法

  由于ArrayList方法底层是数组的实现,因此对于AbstractList的indexOf方法提供了复写,底层采用了数组来实现该方法.

public int indexOf(Object o) {
if (o == 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;
}

五.add方法

  ensureCapacity保证了如果是默认构造函数,那么建立10个容量的数组,不是的话,则数组即将满的时候,扩容数组.(新数组的容量一般情况下都是老数组容量的1.5倍).

public boolean add(E e) {
ensureCapacityInternal(size + 1); // 增加modCount以及容量~
elementData[size++] = e;
return true;
}

六.add(int index,E element)方法

  该方法采用System.arrayCopy方法将index位置及以后的元素全部拷贝到index+1的位置处,并且将数组的长度加1.随后在index索引处赋值.

public void add(int index, E element) {
rangeCheckForAdd(index); ensureCapacityInternal(size + 1);
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}

七.addAll方法.

  采用将Collection集合转化为数组的方式,在调用System.ArrayCopy方法来完成对于数组的增加.

public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // 增加modCount的值
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}

八.removeAll和retainAll方法

  removeAll和retainAll方法通过向同一个方法传入不同的参数,实现移除元素,方法直接在数组对象中记录与给定Collection对象相同的或者不同的元素.

public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
//在此方法中进行removeAll和retainAll方法的实现:
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;//建立一个数组类型的引用指向内存中的数组对象
int r = 0, w = 0;//r遍历数组的索引.w记录相同的元素或者不同的元素
boolean modified = false;
try {
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null; //w索引之前记录了相同的或者不同的元素
modCount += size - w;
size = w;
modified = true;
}
}
return modified;

Java源码初学_ArrayList的更多相关文章

  1. Java源码初学_AbstractList&AbstractCollection

    一.AbstractCollection抽象类:(提供了Collection接口的骨干实现,以减少实现接口所需要的工作) 1.contains方法 contains方法,通过迭代器对于列表的每一个元素 ...

  2. Java源码初学_HashSet&LinkedHashSet

    一.概述 HashSet是建立在HashMap的基础上的,其内部存在指向一个HashMap对象的引用,操作HashSet实际上就是操作HashMap,而HashMap中所有键的值都指向一个叫做Dumm ...

  3. Java源码初学_LinkedHashMap

    一.概述: LinkedHashMap是HashMap的子类,它的基本操作与HashMap相同,与之不同的是,它可以实现按照插入顺序进行排序.也可以通过在构造函数中指定参数,按照访问顺序排序(Link ...

  4. Java源码初学_HashMap

    一.概念 HashMap的实例有两个参数影响其性能:初始容量和加载因子.容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量.加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度.当哈希表 ...

  5. Java源码初学_LinkedList

    一.LinkedList的内部数据结构 LinkedList底层是一个链表的数据结构,采用的是双向链表,基本的Node数据结构代码如下: private static class Node<E& ...

  6. 如何阅读Java源码 阅读java的真实体会

    刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心.   说到技术基础,我打个比 ...

  7. Android反编译(一)之反编译JAVA源码

    Android反编译(一) 之反编译JAVA源码 [目录] 1.工具 2.反编译步骤 3.实例 4.装X技巧 1.工具 1).dex反编译JAR工具  dex2jar   http://code.go ...

  8. 如何阅读Java源码

    刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动.源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比方吧, ...

  9. Java 源码学习线路————_先JDK工具包集合_再core包,也就是String、StringBuffer等_Java IO类库

    http://www.iteye.com/topic/1113732 原则网址 Java源码初接触 如果你进行过一年左右的开发,喜欢用eclipse的debug功能.好了,你现在就有阅读源码的技术基础 ...

随机推荐

  1. [HTML]POST方法和GET方法

    GET方法: function btn_get_click(){ var httpRequest = new XMLHttpRequest(); httpRequest.onreadystatecha ...

  2. Java 期末复习提纲

    Java 开发环境 Java 的特点 面向对象.跨平台.能把中小型程序写成大型程序 开发 Java 的流程 设计类 写代码 重构 Java 程序规范 Javadoc 风格注释 接口以 able 结尾 ...

  3. Arrays.asList()使用注意点

    今天看代码时, 发现书上使用了Arrays.asList()方法, 将一个数组转成了List, 然后说到得到的List不能调用add(), remove()方法添加元素或者删除,带着疑问看了下内部实现 ...

  4. shell 条件判断参数

    -b file 若文件存在且是一个块特殊文件,则为真 -c file 若文件存在且是一个字符特殊文件,则为真 -d file 若文件存在且是一个目录,则为真 -e file 若文件存在,则为真 -f ...

  5. context是什么意思

    context上下文吗,可以解释为程序运行的某一区间之内,提供对这一区间之内操作的一种对象,而且往往这一区间之内得核心操作都需要这个对象来进行 把Context翻译成“上下文”只是不直观罢了,不过也没 ...

  6. WinForm窗体及其控件的自适应

    3步骤: 1.在需要自适应的Form中实例化全局变量   AutoSizeFormClass.cs源码在下方 AutoSizeFormClass asc = new AutoSizeFormClass ...

  7. android MSM8974 上DeviceTree简介

    简介 主要功能是不在代码中硬编码设备信息,而是用专门的文件来描述.整个系统的设备节点会形成一个树,设备节点里可以设置属性.官网在http://www.devicetree.org .入门指南请参考ht ...

  8. (1)编写一个接口:InterfaceA,只含有一个方法int method(int n); (2)编写一个类:ClassA来实现接口InterfaceA,实现int method(int n)接口方 法时,要求计算1到n的和; (3)编写另一个类:ClassB来实现接口InterfaceA,实现int method(int n)接口 方法时,要求计算n的阶乘(n!); (4)编写测试类E测试

    package a; public interface InterfaceA { int method(int n); } package a; public class ClassA impleme ...

  9. 【转载】COM:IUnknown、IClassFactory、IDispatch

    原文:COM:IUnknown.IClassFactory.IDispatch COM组件有三个最基本的接口类,分别是IUnknown.IClassFactory.IDispatch. COM规范规定 ...

  10. 【转载】为什么CPU有多层缓存

    原文:为什么CPU有多层缓存 http://mp.weixin.qq.com/s?__biz=MzI1NDM2Nzg5Mw==&mid=2247483712&idx=1&sn= ...