Java数据结构ArrayList

/**
* <html>
* <body>
* <P> Copyright JasonInternational</p>
* <p> All rights reserved.</p>
* <p> Created on 2018年6月27日 下午6:13:40</p>
* <p> Created by Jason </p>
* </body>
* </html>
*/
package cn.ucaner.sourceanalysis.list; import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.RandomAccess; /**
* @Package:cn.ucaner.sourceanalysis
* @ClassName:ArrayList
* @Description: <p> ArrayList 源码分析 </p>
* <pre>ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。</br>
* ArrayList不是线程安全的,只能在单线程环境下,多线程环境下可以考虑用collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,
* 也可以使用concurrent并发包下的CopyOnWriteArrayList类。
*
* ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,
* 实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问,实现了Cloneable接口,能被克隆。
*
* </pre>
*
* <note>
* 1.注意其三个不同的构造方法。
* 无参构造方法构造的ArrayList的容量默认为10,带有Collection参数的构造方法,将Collection转化为数组赋给ArrayList的实现数组elementData
* 2.注意扩充容量的方法ensureCapacity。
* ArrayList在每次增加元素(可能是1个,也可能是一组)时,都要调用该方法来确保足够的容量.
* 当容量不足以容纳当前的元素个数时,就设置新的容量为旧的容量的1.5倍加1,
* 如果设置后的新容量还不够,则直接新容量设置为传入的参数(也就是所需的容量).而后用Arrays.copyof()方法将元素拷贝到新的数组
* 当容量不够时,每次增加元素,都要将原来的元素拷贝到一个新的数组中,非常之耗时,
* 也因此建议在[事先能确定元素数量]的情况下,才使用ArrayList,否则建议使用LinkedList. Rember!
* 3.ArrayList的实现中大量地调用了Arrays.copyof()和System.arraycopy()方法
* </note>
* @Author: - Jason
* @CreatTime:2018年6月27日 下午6:13:40
* @Modify By:
* @ModifyTime: 2018年6月27日
* @Modify marker:
* @version V1.0
*/
/*
REMARK: 1.Arrays.copyof()
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
} public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
该方法实际上是在其内部又创建了一个长度为newlength的数组,调用System.arraycopy()方法,将原来数组中的元素复制到了新的数组中
该方法被标记了native,调用了系统的C/C++代码,在JDK中是看不到的,但在openJDK中可以看到其源码
该函数实际上最终调用了C语言的memmove()函数,因此它可以保证同一个数组内元素的正确复制和移动,比一般的复制方法的实现效率要高很多,很适合用来批量处理数组.
Java强烈推荐在复制大量数组元素时用该方法,以取得更高的效率 [ System.arraycopy() ] Remeber 注意ArrayList的两个转化为静态数组的toArray方法。
第一个,Object[] toArray()方法。
该方法有可能会抛出java.lang.ClassCastException异常,如果直接用向下转型的方法,将整个ArrayList集合转变为指定类型的Array数组,
便会抛出该异常,而如果转化为Array数组时不向下转型,而是将每个元素向下转型,则不会抛出该异常,
显然对数组中的元素一个个进行向下转型,效率不高,且不太方便。 第二个, T[] toArray(T[] a)方法。
该方法可以直接将ArrayList转换得到的Array进行整体向下转型(转型其实是在该方法的源码中实现的),
且从该方法的源码中可以看出,参数a的大小不足时,内部会调用Arrays.copyOf方法,该方法内部创建一个新的数组返回,因此对该方法的常用形式如下:
public static Integer[] vectorToArray2(ArrayList<Integer> v) {
Integer[] newText = (Integer[])v.toArray(new Integer[0]);
return newText;
} ArrayList基于数组实现,可以通过下标索引直接查找到指定位置的元素,因此查找效率高,但每次插入或删除元素,就要大量地移动元素,插入删除元素的效率低. 在查找给定元素索引值等的方法中,源码都将该元素的值分为null和不为null两种情况处理,ArrayList中允许元素为null。
*/ public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ //序列版本号
private static final long serialVersionUID = 7192670450143374735L; // ArrayList基于该数组实现,用该数组保存数据
private transient Object[] elementData; // ArrayList中实际数据的数量
private int size; /**
* ArrayList 带容量大小的构造函数.
* @param initialCapacity
*/
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("[Java-Core-Advanced]Illegal Capacity: "+ initialCapacity);
this.elementData = new Object[initialCapacity];// 新建一个数组
} /**
* ArrayList 无参构造函数 - 默认容量是10
*/
public ArrayList() {
this(10);
} /**
* 创建一个包含collection的ArrayList
* @param c 集合
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} /**
* @Description: 将当前容量值设为实际元素个数
* @Autor: Jason
* @Date: 2018年6月27日
*/
public void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
} /**
* @Description: 确定ArrarList的容量
* 若ArrayList的容量不足以容纳当前的全部元素,设置 新的容量="(原始容量x3)/2 + 1"
* @param minCapacity void
* @Autor: Jason
* @Date: 2018年6月27日
*/
@SuppressWarnings("unused")
public void ensureCapacity(int minCapacity) {
// 将"修改统计数"+1,该变量主要是用来实现fail-fast机制的
modCount++;
int oldCapacity = elementData.length;
// 若当前容量不足以容纳当前的元素个数,设置 新的容量="(原始容量x3)/2 + 1"
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
//如果还不够,则直接将minCapacity设置为当前容量
if (newCapacity < minCapacity) {
newCapacity = minCapacity;
}
elementData = Arrays.copyOf(elementData, newCapacity);
}
} /**
* 添加元素e
*/
public boolean add(E e) {
// 确定ArrayList的容量大小
ensureCapacity(size + 1); // Increments modCount!!
// 添加e到ArrayList中
elementData[size++] = e;
return true;
} /**
* 返回ArrayList的实际大小
*/
@Override
public int size() {
return size;
} /**
* ArrayList是否包含Object(o)
*/
public boolean contains(Object o) {
return indexOf(o) >= 0;
} /**
* 返回ArrayList是否为空
*/
public boolean isEmpty() {
return size == 0;
} /**
* 正向查找,返回元素的索引值
*/
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;
} /**
* 反向查找,返回元素的索引值 返回元素(o)的索引值
*/
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
} /**
* 返回ArrayList的Object数组
*/
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
} /**
* 返回ArrayList元素组成的数组
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
// 若数组a的大小 < ArrayList的元素个数;
// 则新建一个T[]数组,数组大小是"ArrayList的元素个数",并将"ArrayList"全部拷贝到新数组中
if (a.length < size)
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
// 若数组a的大小 >= ArrayList的元素个数;
// 则将ArrayList的全部元素都拷贝到数组a中。
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
} /**
* 获取index位置的元素值
*/
@SuppressWarnings("unchecked")
@Override
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
} /**
* 设置index位置的值为element return oderValue
*/
@SuppressWarnings("unchecked")
public E set(int index, E element) {
RangeCheck(index);
E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
} /**
* @Description: RangeCheck
* @param index 索引
* @Autor: Jason
* @Date: 2018年6月27日
*/
private void RangeCheck(int index) {
if (index >= size) {
throw new IndexOutOfBoundsException("[Java-Core-Advanced]Index: "+index+", Size: "+size);
}
} /**
* 将e添加到ArrayList的指定位置
*/
public void add(int index, E element) {
if (index > size || index < 0) {
throw new IndexOutOfBoundsException("[Java-Core-Advanced]Index: "+index+", Size: "+size);
}
ensureCapacity(size+1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
} /**
* 删除ArrayList指定位置的元素
*/
public E remove(int index) {
RangeCheck(index);
modCount++;
@SuppressWarnings("unchecked")
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0) {
System.arraycopy(elementData, index+1, elementData, index,numMoved);
}
elementData[--size] = null; // Let gc do its work 置Null
return oldValue;
} /**
* 删除ArrayList的指定元素
*/
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;
} /**
* @Description: 快速删除第index个元素
* @param index
* @Autor: Jason
* @Date: 2018年6月27日
*/
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
// 从"index+1"开始,用后面的元素替换前面的元素。
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 将最后一个元素设为null
elementData[--size] = null; // Let gc do its work
} /**
* 清空ArrayList,将全部的元素设为null
*/
public void clear() {
modCount++;
for (int i = 0; i < size; i++) {
elementData[i] = null;
}
size = 0;
} /**
* 将集合c追加到ArrayList中
*/
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount oldSize+newSize
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
} /**
* 从index位置开始,将集合c添加到ArrayList
*/
public boolean addAll(int index, Collection<? extends E> c) {
if (index > size || index < 0) {
throw new IndexOutOfBoundsException( "[Java-Core-Adevanced]Index: " + index + ", Size: " + size);
}
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount int numMoved = size - index;
if (numMoved > 0) {
System.arraycopy(elementData, index, elementData, index + numNew,numMoved);
}
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
} /**
* 删除fromIndex到toIndex之间的全部元素
*/
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved); // Let gc do its work
int newSize = size - (toIndex-fromIndex);
while (size != newSize) {
elementData[--size] = null;
}
} /**
* 克隆函数
*/
public Object clone() {
try {
@SuppressWarnings("unchecked")
ArrayList<E> v = (ArrayList<E>) super.clone();
// 将当前ArrayList的全部元素拷贝到v中
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) { //Cloneable
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
} /**
* @Description: java.io.Serializable的写入函数 将ArrayList的"容量,所有的元素值"都写入到输出流中
* @param s
* @throws java.io.IOException
* @Autor: Jason
* @Date: 2018年6月27日
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// 写入"数组的容量"
s.writeInt(elementData.length);
// 写入“数组的每一个元素”
for (int i=0; i<size; i++)
s.writeObject(elementData[i]); if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
} } /**
*
* @Description: Java.io.Serializable的读取函数:根据写入方式读出 先将ArrayList的“容量”读出,然后将“所有的元素值”读出
* @param s
* @throws java.io.IOException
* @throws ClassNotFoundException void
* @Autor: Jason
* @Date: 2018年6月27日
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// 从输入流中读取ArrayList的“容量”
int arrayLength = s.readInt();
Object[] a = elementData = new Object[arrayLength];
// 从输入流中将“所有的元素值”读出
for (int i=0; i<size; i++)
a[i] = s.readObject();
} //just for test
public static void main(String[] args) {
}
}

  

Java数据结构ArrayList的更多相关文章

  1. Java数据结构-ArrayList最细致的解析笔记

    ArrayList是一个类,这个类有一个数组参数elementData,ArrayList集合中的元素正是保存在这个数组中,它继承了数组查询的高性能,参考第3篇.ArrayList还封装了很多方法,便 ...

  2. JAVA数据结构--ArrayList动态数组

    在计算机科学中,动态数组,可扩展数组,可调整数组,动态表,可变数组或数组列表是一种随机存取可变大小列表数据结构,允许添加或删除元素.它提供许多现代主流编程语言的标准库.动态数组克服了静态数组的限制,静 ...

  3. Java数据结构之表的增删对比---ArrayList与LinkedList之一

    一.Java_Collections表的实现 与c不同Java已经实现并封装了现成的表数据结构,顺序表以及链表. 1.ArrayList是基于数组的实现,因此具有的特点是:1.有索引值方便查找,对于g ...

  4. 词典的实现(3)--使用JAVA类库ArrayList实现Map数据结构

    1,在词典的实现(2)-借助顺序表(数组)实现词典文章中使用了自定义的数组代替ArrayList,并实现了Map数据结构的基本功能.而借助JAVA类库ArrayList类的一些方法可以更加容易地实现M ...

  5. Java 的 ArrayList 的底层数据结构

    1. 数据结构--ArrayList源码摘要 ublic class ArrayList<E> extends AbstractList<E> implements List& ...

  6. Java基础-ArrayList和LinkedList的区别

    大致区别:  1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构. 2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为Lin ...

  7. java中ArrayList 、LinkList区别

    转自:http://blog.csdn.net/wuchuanpingstone/article/details/6678653 个人建议:以下这篇文章,是从例子说明的方式,解释ArrayList.L ...

  8. Java数据结构之树和二叉树(2)

    从这里始将要继续进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来 ...

  9. Java数据结构之树和二叉树

    从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...

随机推荐

  1. arcgis python 开启编辑会话和编辑操作、在表中创建行、停止编辑操作以及提交编辑会话。

    import arcpy import os fc = 'Database Connections/Portland.sde/portland.jgp.schools' workspace = os. ...

  2. Flutter移动电商实战 --(41)详细页_数据接口的调试

    建立数据模型层,我们的业务逻辑分开,然后进行后台数据的调试 生成model类 json数据: { "code": "0", "message" ...

  3. 解读typescript中 super关键字的用法

    解读typescript中 super关键字的用法 传统的js,使用prototype实现父.子类继承.如果父.子类有同名的方法,子类去调用父类的同名方法需要用 “父类.prototype.metho ...

  4. MongoDB查询报错:class com.mongodb.MongoSecurityException: Exception authenticating MongoCredential

    异常日志: -- ::, [http-nio--exec-] DEBUG [java.sql.Connection] - ooo Connection Opened -- ::, [http-nio- ...

  5. 怎样提交社区项目Karbor的Bug?

    1.登录社区Karbor Launchpad地址: https://bugs.launchpad.net/karbor/+filebug 输出bug简介,点击Next按钮. 2.填写Bug描述,完成B ...

  6. PAT 甲级 1035 Password (20 分)(简单题)

    1035 Password (20 分)   To prepare for PAT, the judge sometimes has to generate random passwords for ...

  7. java中byte数组,二进制binary安装chunk大小读取数据

    int CHUNKED_SIZE = 8000; public void recognizeText(byte[] data) throws InterruptedException, IOExcep ...

  8. eNSP——静态路由的基本配置

    原理: 静态路由是指用户或网络管理员手工配置的路由信息.当网络的拓扑结构或链路状态发生改变时,需要网络管理人员手工修改静态路由信息. 相比于动态路由协议,静态路由无需频繁地交换各自的路由表,配置简单, ...

  9. UIPath工具来取得邮件里面的添付文件及邮件内容

    下图是得到Outlook邮件附件的示意图 下面的图是对UIPath的属性的设定.最重要的是两个文件夹要保持一致.

  10. 《Tsinghua os mooc》第21~22讲 文件系统

    第二十一讲 文件系统 文件系统是操作系统中管理持久性数据的子系统,提供数据存储和访问功能. 组织.检索.读写访问数据 大多数计算机系统都有文件系统 Google 也是一个文件系统 文件是具有符号名,由 ...