注:转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/5965205.html 

    代码已移植:https://github.com/ygj0930/MyArrayList  大家fork之余随手给我个star呀~

ArrayList是我们常用的集合类之一,其实它的实现机制很简单,底层还是使用了一个传统的Array数组来保存数据的。而动态的实现,只不过是定义了其在长度不足时创建一个更大的数组并把原数组的数据复制过去罢了!而对其保存的数据的增删查该操作,也只不过是封装了一系列最基本的操作数组数据的动作而已。下面,我把自己实现的简略版ArrayList贴上来,供伙伴们参考。

  

public class MyArrayList<E> {
public transient E[] elements;//底层的泛型数组用来保存元素
/*
这里用transient修饰数组,用transient关键字标记的成员变量不参与序列化过程。
serialization(序列化)提供了一种持久化对象实例的机制,通过序列化可以把对象输出到文档中保存。
而不想某个对象参与序列化,就可以用transient把该对象排除在外。
*/
public int size;//size记录数组当前的有效元素个数 //实现三个构造方法
public MyArrayList(int n) {
if (n > 0) {
this.elements = (E[])new Object[n];//创建容量为n的数组
this.size=0;//一开始数组里个数为0
} else {
throw new IllegalArgumentException("Illegal Capacity: "+n);
}
}
public MyArrayList() {
this.elements = (E[])new Object[10];
this.size=0;
}
public MyArrayList(Collection<Object> c) {
elements = (E[])c.toArray();//将集合转换为数组,数组容量为集合元素个数
if ((size = elements.length) != 0) { //此时数组元素个数等于数组容量
elements = (E[])Arrays.copyOf(elements, size, Object[].class);}
} //实现容量扩充
public void ensureCapacity(int newCapacity){
int curr=elements.length;
if(newCapacity>curr){
elements=Arrays.copyOf(elements, newCapacity);
}
} //调整底层数组容量以契合当前元素数量,避免空元素部分太多而浪费内存。size是数组中实际存在的元素个数
public void trimToSize(){
int curr=elements.length;
if(size<curr){
elements=Arrays.copyOf(elements, size);
}
} //实现下标检查:避免访问越界内存
public void rangeCheck(int requestIndex){
if(requestIndex<0||requestIndex>size){
throw new IndexOutOfBoundsException(); }
} //实现基本操作:增、删、查、改 //增
//在某个位置插入新元素
public void add(int index,E element){
this.rangeCheck(index);//先检查插入位置的合法性 //再检查当前数组元素个数是否已经达到最大值,即达到数组容量,是,则扩充数组
if(size==elements.length){
ensureCapacity(elements.length*2+1);
} //将插入位置的原数据以及其后的数据往后移动一位,腾出空间
System.arraycopy(elements, index, elements, index+1, 1); //插入相应位置,并将数组元素个数加一
elements[index]=element;
++size;
} //在数组末尾追加一个元素
public void add(E element){
this.add(size, element);//实则等同于在elements[size]处插入元素
} //将一个集合插入到数组某位置
public void addAll(int index,Collection<? extends E> c){
rangeCheck(index); //获取插入元素以及个数
E[] newEs=(E[])c.toArray();
int newLength=newEs.length; //扩充数组容量
ensureCapacity(size+newLength+1); //计算插入位置以及其后元素的个数,即:需要右移的元素个数
int move=size-index; //调用System.arraycopy()方法进行数组的大量数据移动操作。
/*
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
方法解读:第一个参数指明数据的来源数组,第二个参数说明数据源的起始位置
第三个参数说明数据去向的目标数组,第四个参数说明数据在目标数组中存放时的起始位置,最后一个参数说明移动的数据长度(个数)。
该函数调用了C语言的memmove()函数,比一般的复制方法的实现效率要高很多,也安全很多,很适合用来批量处理数组。
强烈推荐在复制大量数组元素时用该方法,以取得更高的效率。
*/
//将原数组index~size范围的元素移动,腾出位置
if(move>0){
System.arraycopy(elements, index, elements, index+newLength, move);
}
//将插入数组元素复制到elements数组中腾出的位置
System.arraycopy(newEs,0 , elements, index, newLength); size+=newLength;//元素个数增加
} //将一个集合插入到数组末尾
public void addAll(Collection<? extends E> c){
this.addAll(size, c);//相当于在原数组elements[size]处开始,插入一个集合
} //删
//移除指定位置的元素
public E remove(int index){
rangeCheck(index); E oldelement=elements[index]; //原位置后面的元素左移
System.arraycopy(elements, index+1, elements, index, size-index-1); elements[size]=null;//修改原数组最后一个元素位置为空
--size;//修改元素个数 return oldelement;
}
//移除某个值的元素
public boolean remove(E element){
boolean index=false;
for(int i=0;i<size;++i){
if(element.equals(elements[i])){//若找到该值
index=true;//说明有该值,可以执行移除,结果为true。否则,结果false
this.remove(i);//则通过下标来移除
}
}
return index;
}
//移除某个 范围内 的元素(不包括end)
public void removeRange(int start,int end){
int move=size-end;
System.arraycopy(elements, end,elements, start, move); //修改左移留下的位置为空
for(int i=size-1;i>(size-(end-start)-1);--i){
elements[i]=null;
} size-=(end-start);
} //查
//获取某位置的元素
public E get(int index){
rangeCheck(index);
return elements[index];
} //改
//修改某位置的元素
public void set(int index,E newElement){
rangeCheck(index); elements[index]=newElement;
} //转变为普通数组
public E[] toArray()
{
E[] array=(E[]) new Object[size];
System.arraycopy(elements, 0,array,0, size);
return array;
} public static void main(String[] args) {
MyArrayList<Integer> testMyArrayList=new MyArrayList<Integer>(); System.out.println(testMyArrayList.size); testMyArrayList.add(1);
testMyArrayList.add(2);
testMyArrayList.add(3);
testMyArrayList.add(4);
testMyArrayList.add(5); System.out.println(testMyArrayList.size);
System.out.println(testMyArrayList.get(3)); testMyArrayList.removeRange(1, 3); System.out.println(testMyArrayList.size);
System.out.println(testMyArrayList.get(2));
} }

MyArrayList——自己实现ArrayList的更多相关文章

  1. 造轮子ArrayList

    这篇博客实现一个简单的ArrayList集合.博客里的代码首先根据自己的想法实现,在走不动的情况下会去参考JDK源代码.所以阅读本文,不要抱着跟JDK源码对比的心态.于我个人而言,国庆期间,纯属娱乐. ...

  2. 【Java集合】ArrayList源码分析

    ArrayList是日常开发中经常使用到的集合,其底层采用数组实现,因此元素按序存放.其优点是可以使用下标来访问元素,时间复杂度是O(1).其缺点是删除和增加操作需要使用System.arraycop ...

  3. JavaSE| 集合

    集合 l  Collection 层次结构中的根接口.Collection 表示一组对象,这些对象也称为 collection 的元素.一些 collection 允许有重复的元素,而另一些则不允许. ...

  4. 乐字节-Java8核心特性实战-接口默认方法

    JAVA8已经发布很久,是自java5(2004年发布)之后Oracle发布的最重要的一个版本.其中包括语言.编译器.库.工具和JVM等诸多方面的新特性,对于国内外互联网公司来说,Java8是以后技术 ...

  5. .NET 面试题: C# override && overloading (C# 覆写 && 重载)

    1 1 1 .NET 面试题, C# ,override , overloading, 覆写, 重载,.NET,ASP.NET, override (覆写/重写): 方法名相同,参数的个数和类型相同, ...

  6. 阿里早期Android加固代码的实现分析

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/78320445 看雪上有作者(寒号鸟二代)将阿里移动早期的Android加固进行了逆 ...

  7. MyArrayList——实现自己的ArrayList!

    注:转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/5965205.html ArrayList是我们常用的集合类之一,其实它的实现机制很简单,底层还是使用了一个 ...

  8. 实现MyArrayList类深入理解ArrayList

    ArrayList简介 ArrayList是一个动态数组,Array的复杂版本,它提供了动态的增加和减少元素,实现了ICollection和IList接口,灵活的设置数组的大小等好处. MyArray ...

  9. 模仿.NET框架ArrayList写一个自己的动态数组类MyArrayList,揭示foreach实现原理

    通过.NET反编译工具可以查看到ArrayList内部的代码,发现ArrayList并非由链表实现,而是由一个不断扩容的数组对象组成. 下面模仿ArrayList写一个自己的MyArrayList. ...

随机推荐

  1. 好汉两个半第十二季/全集Two and a Half Men迅雷下载

    本季Two And A Half Men Season 12 (2014)看点:<好汉两个半>的“半个”是因为第一季播出时杰克年纪太小,只能算半个.故事就在这三个主角和他们周围的女人中发生 ...

  2. 【JAVA与C#比较】其它

    从语言方面的知识点来说,这应该是最后一篇有关java和C#的比较了.如果要了解两者具体各知识点的异同,请查看前面的相关文章,不过后面有可能存在,不能放到前面文章所列知识点的情况,应该就会补充到这里吧. ...

  3. 【转】各种 NoSQL 的比较

    转自 : http://linux.cn/article-2177-1.html 来源:Linux中国  原文:http://linux.cn/article-2177-1.html     即使关系 ...

  4. 【keytool jarsigner工具的使用】Android 使用JDK1.7的工具 进行APK文件的签名,以及keystore文件的使用

    一个android apk的编译过程 请参考: http://www.2cto.com/kf/201312/261475.html 典型的编译过程: aapt( Android Asset Packa ...

  5. 奇怪吸引子---Arneodo

    奇怪吸引子是混沌学的重要组成理论,用于演化过程的终极状态,具有如下特征:终极性.稳定性.吸引性.吸引子是一个数学概念,描写运动的收敛类型.它是指这样的一个集合,当时间趋于无穷大时,在任何一个有界集上出 ...

  6. WCF Ajax Json的应用

    WCF Ajax 的应用网上实际上有很多, 如: Ajax与Wcf交互-JSON jQuery调用WCF服务传递JSON对象 WCF以Json格式返回对象,客户端以JS调用显示 关于SoapUI的介绍 ...

  7. [leetcode]Unique Binary Search Trees @ Python

    原题地址:https://oj.leetcode.com/problems/unique-binary-search-trees/ 题意: Given n, how many structurally ...

  8. Backbone.js 使用模板

    实际的应用中会使用到模板,Model 等,而模板又是进阶的基础.所以这里介绍在 View 中使用模板,以及如何向模板填充值,模板可以用字符串,或是用 <script type="tex ...

  9. JS获取当前网页内容,创建文件并下载,URL.createObjectURL和URL.revokeObjectURL

    有时候需要在前端侧对于动态生成的内容进行下载,比如页面上某一段文本信息,再比如对页面进行分享的时候,希望分享图片是页面内容的实时截图,此时,这个图片就是动态的,纯HTML显然是无法满足我们的需求的,借 ...

  10. 浅谈 Adaboost 算法

    http://blog.csdn.net/haidao2009/article/details/7514787 菜鸟最近开始学习machine learning.发现adaboost 挺有趣,就把自己 ...