java(6) ArrayList源码
系统环境: JDK 1.7
成员变量
//默认的初始化数组大小
private static final int DEFAULT_CAPACITY = 10; //空的对象数组
private static final Object[] EMPTY_ELEMENTDATA = {}; //声明对象数组,不可序列化 transient
private transient Object[] elementData; //数组的大小
private int size;
构造方法
1.带有容量initialCapacity的构造方法
public ArrayList(int initialCapacity) {
    super();
    //参数小于0 则抛出异常
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
    //new一个该大小的object数组赋给elementData
    this.elementData = new Object[initialCapacity];
}
2.不带参数的构造方法
public ArrayList() {
    super();
    this.elementData = EMPTY_ELEMENTDATA;
}    
3.带参数Collection的构造方法
public ArrayList(Collection<? extends E> c) {
    //将 c 转换为对象数据并赋值给elementData
    elementData = c.toArray();
    //获取数组大小
    size = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, size, Object[].class);
}    
注:c.toArray()返回的类型可能是非Object[]类型,如:Arrays.asList().toArray(),详情参考《关于 ArrayList.toArray()和Arrays.asList().toArray()方法》
总结:通过三个构造方法 我们发现ArrayList的实质就是封装了对数组的一些操作,通过这些操作,从而达到我们需要的目的
Add方法分析
public boolean add(E e) {
    // 确保当前的数组大小可以装的下传入的对象e
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    // 在内部数组中存放对象,并将索引值+1
    elementData[size++] = e;
    return true;
}
public void add(int index, E element) {
    // 确保传入的数值没有越界
    rangeCheckForAdd(index);
    // 确保当前的数组大小可以装的下传入的对象e
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}    
private void ensureCapacityInternal(int minCapacity) {
    //针对new ArrayList()这种初始化方法有效,只有无参构造方法让内部数组等于empty。
    if (elementData == EMPTY_ELEMENTDATA) {
        // 确保 minCapacity 最小值是 10
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    //
    ensureExplicitCapacity(minCapacity);
}    
//判断是不是真的需要扩容。
//如果我们用new ArrayList()初始化,根据上边的代码 minCapacity=10,而现在内部类真正的大小elementData.length是 0,所以需要扩容。
//如果我们用new ArrayList(20)初始化,内部数组在构造方法内已经初始化了,内部数组长度为20,而在add方法的时候,第一个操作传入的是size+1,即0+1。
//所以到达这个判断的时候,最小需要的容量为1,而长度为20 ,必然不需要扩容
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}    
//数组真正的扩容操作
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    // 新长度为原数组长度的1.5倍  整数右移1为 相当于除2
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}    
Remove方法分析
remove方法有2个,传入的参数分别是int和Object
public E remove(int index) {
    //判断传入的数字是否在合理范围内,即是否小于数组内真实的数据个数
    rangeCheck(index);
    modCount++;
    E oldValue = elementData(index);//将要remove的索引位置的元素取出
    //将内部数组中空出来的那个位置之后的元素移动到前边去
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    // 将最后一位置空,size自减
    elementData[--size] = null; // clear to let GC do its work
    return oldValue; // 返回移除的那个数据
}    
//另一个重载方法,实质上是一样的
public boolean remove(Object o) {
    if (o == 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; // clear to let GC do its work
}
//判断传入的数字是否在合理范围内
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}    
@SuppressWarnings("unchecked")
E elementData(int index) {
    return (E) elementData[index];
}    
System.arraycopy()方法
*5个参数的含义分别是:
--src 源数组.
--srcPos 源数组中的起始位置。
--dest 目标数组。
--destPos 目标数据中的起始位置。
--length 要复制的数组元素的数目
int[] arr1 = { 0, 1, 2, 3, 4, 5 };
int[] arr2 = { 6, 7, 8, 9, 10, 11};
// 将arr1的元素复制到arr2中,从arr1的索引位置为3开始,复制长度为1个,到arr2中,arr2从索引为0的位置开始接受复制
System.arraycopy(arr1, 3, arr2, 0, 1);
// 所以最后结果是--  arr1:{ 0, 1, 2, 3, 4, 5 }   arr2:{ 3, 7, 8, 9, 10, 11}
System.out.println(Arrays.toString(arr1));
System.out.println(Arrays.toString(arr2));
整理自《http://blog.csdn.net/zw0283/article/details/51122255》
java(6) ArrayList源码的更多相关文章
- Java基础 ArrayList源码分析 JDK1.8
		
一.概述 本篇文章记录通过阅读JDK1.8 ArrayList源码,结合自身理解分析其实现原理. ArrayList容器类的使用频率十分频繁,它具有以下特性: 其本质是一个数组,因此它是有序集合 通过 ...
 - Java中ArrayList源码分析
		
一.简介 ArrayList是一个数组队列,相当于动态数组.每个ArrayList实例都有自己的容量,该容量至少和所存储数据的个数一样大小,在每次添加数据时,它会使用ensureCapacity()保 ...
 - Java集合ArrayList源码解读
		
最近在回顾数据结构,想到JDK这样好的代码资源不利用有点可惜,这是第一篇,花了心思.篇幅有点长,希望想看的朋友认真看下去,提出宝贵的意见. :) 内部原理 ArrayList 的3个字段 priva ...
 - Java集合-ArrayList源码解析-JDK1.8
		
◆ ArrayList简介 ◆ ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了List, RandomAcc ...
 - Java集合——ArrayList源码详解
		
) ArrayList 实现了RandomAccess, Cloneable, java.io.Serializable三个标记接口,表示它自身支持快速随机访问,克隆,序列化. public clas ...
 - 【thinking in java】ArrayList源码分析
		
简介 ArrayList底层是数组实现的,可以自增扩容的数组,此外它是非线程安全的,一般多用于单线程环境下(Vector是线程安全的,所以ArrayList 性能相对Vector 会好些) Array ...
 - Java基础—ArrayList源码浅析
		
注:以下源码均为JDK8的源码 一. 核心属性 基本属性如下: 核心的属性其实是红框中的两个: //从注释也容易看出,一个是集合元素,一个是集合长度(注意是逻辑长度,即元素的个数,而非数组长度) 其中 ...
 - java.util.ArrayList源码分析
		
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess ...
 - java的ArrayList源码摘要
		
ArrayList本质上是一组对象数组,ArrayList有三种构造方法 1.指定长度创建ArrayList,2.默认长度为10创建.3,用旧的集合创建一个ArrayList. 对ArrayList的 ...
 - Java集合-ArrayList源码分析
		
目录 1.结构特性 2.构造函数 3.成员变量 4.常用的成员方法 5.底层数组扩容原理 6.序列化原理 7.集合元素排序 8.迭代器的实现 9.总结 1.结构特性 Java ArrayList类使用 ...
 
随机推荐
- js 按键
			
原文:https://www.cnblogs.com/lunlunshiwo/p/8705856.html 上周临近周末休息的时候,一个同事跑过来了,对我说:“阿伦啊,有一个页面出问题了,火狐浏览器所 ...
 - linux cfs调度器_模型实现
			
调度器真实模型的主要成员变量及与抽象模型的对应关系 I.cfs_rq结构体 a) struct sched_entity *curr 指向当前正在执行的可调度实体.调度器的调度单位 ...
 - Spring Boot 添加JSP支持【转】
			
Spring Boot 添加JSP支持 大体步骤: (1) 创建Maven web project: (2) 在pom.xml文件添加依赖: (3) ...
 - SpringMVC工作原理详解
			
先来看一下什么是 MVC 模式 MVC 是一种设计模式. MVC 的原理图如下: SpringMVC 简单介绍 SpringMVC 框架是以请求为驱动,围绕 Servlet 设计,将请求发给控制器,然 ...
 - Python 面向对象详解
			
Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本章节我们将详细介绍Python的面向对象编程. 如果你以前没有接触过面向对象的编程语言,那你 ...
 - my-small.ini、my-medium.ini、my-large.ini、my-huge.ini文件的作用
			
安装完mysql之后或者是下载的免安装版解压之后,默认是没有my.ini文件的.但是,有几个类似的文件,如my-small.ini.my-medium.ini.my-large.ini.my-huge ...
 - PHP压缩html网页代码原理(清除空格,换行符,制表符,注释标记)
			
本博启用了一个叫wp super cache的页面压缩工具, 源代码没有去查看,不过原理很简单. 我们可以自己动手书写一个压缩脚本. 清除换行符,清除制表符,去掉注释标记 .它所起到的作用不可小视. ...
 - ios开发之--理解NSStringDrawingOptions每个选项的用法与意义
			
typedef NS_OPTIONS(NSInteger, NSStringDrawingOptions) { NSStringDrawingUsesLineFragmentOrigin = < ...
 - mysql 查询锁表
			
1)使用情景“判断通过后写入数据库”,这个一般是不会有问题的, 但并发访问的时候就不太好搞.因为写入(insert)是需要时间的,假设现在有两个并发请求,(假设第一个访问是最后一个符合条件的写入请求, ...
 - RF实现多次失败重跑结果合并的基础方法和优化方法
			
实现思路:通过分次执行失败案例重跑,然后通过结果文件合并命令实现多次失败重跑结果文件的合并,并输出合并后的log和report文件: 说明:具体失败案例重跑命令和结果文件合并命令请参考本博客其他相关章 ...