一.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. Firefox浏览器设置字符编码格式

    按照网上说的:工具 -> 选项 -> 内容 -> 字体&颜色 -> 高级 -> 字体编码,根本没有找到utf-8,还是把浏览器定制一下吧,看源文件的时候也可以用, ...

  2. Kernel启动时 驱动是如何加载的module_init,加载的次序如何;略见本文

    Init.h中有相关initcall的启动次序,在system.map中可看出具体的__initcall指针的前后次序 #define pure_initcall(fn) __define_initc ...

  3. 2016年12月14日 星期三 --出埃及记 Exodus 21:9

    2016年12月14日 星期三 --出埃及记 Exodus 21:9 If he selects her for his son, he must grant her the rights of a ...

  4. 查看centos是多少位的系统命令

    打开命令行 运行下面命令 uname -i 如果是64位系统会显示x86_64 如果显示的是i386则是系统是32位

  5. Linux 性能监控、测试、优化工具

    Linux 平台上的性能工具有很多,眼花缭乱,长期的摸索和经验发现最好用的还是那些久经考验的.简单的小工具.系统性能专家 Brendan D. Gregg 在最近的 LinuxCon NA 2014 ...

  6. Spring.Net 技术简介 IOC and DI

    一 简单介绍            IOC 控制转移,就是将创建放到容器里,从而达到接耦合的目的,DI是 在容器创建对象的时候,DI读取配置文件,然后给对象赋默认值,两者一般结合使用,实现注入.   ...

  7. DataGridView的自定义列排序

    1,将需要进行排序的列做属性的设置 this.colUserName.SortMode = DataGridViewColumnSortMode.Programmatic; 2,添加列的事件 //点击 ...

  8. Perform Cut Copy Paste Operations Using Cut_Region Copy_Region Paste_Region Commands In Oracle Forms

    You can do Select, Cut, Copy and Paste operations on text items in Oracle Forms using Select_All, Cu ...

  9. 基于Microchip单片机的触摸感应技术

    Microchip提供两种电容式触摸感应解决方案,一种为张驰振荡器方式,即通过检测触摸感应电容充放电的频率变化,来检测是否有键按下,根据单片机集成的硬件资源不同,另一种通过Microchip单片机集成 ...

  10. linux系统:rm-rf执行以后,怎么办?我来教你恢复文件。

    记得我当时也犯过这个错误 rm -rf /* 傻傻的盯着屏幕看... 还好当时是在自己的虚拟机里,没什么数据,打镜像恢复回来就好了.今天看到这篇文章,备用!嗯 是的 万一哪天脑抽了 --------- ...