package test;

import java.util.Arrays;
import java.util.Collection; public class MyArrayList<E> { //存储数据
private Object[] values; //已经使用的容量
private int size; //修改次数
private int modCount; /**
* 根据给定容量初始化
* @param initialCapacity
*/
public MyArrayList(int initialCapacity){
if(initialCapacity > ){//按照给定的容量大小初始化数组
values = new Object[initialCapacity];
}else if(initialCapacity == ){
values = new Object[]{};
}else{
throw new IllegalArgumentException("非法初始化容量: "+
initialCapacity);
} } /**
* 默认初始化方法
*/
public MyArrayList(){
this();
} /**
* 用集合初始化一个ArrayList
* @param c
*/
public MyArrayList(Collection c){
values = c.toArray();
if (values.length != ) {
size = values.length;
if (values.getClass() != Object[].class)
values = Arrays.copyOf(values, size, Object[].class);
}else{
values = new Object[]{};
}
}
/**
* 检查是否数组越界了
* @param index
*/
private void rangeCheck(int index) {
if (index >= size || index < )
throw new IndexOutOfBoundsException("数组越界了");
} /**
* 替换原数组中的值,并且将原值返回
* @param index
* @param element
* @return
*/
public E set(int index,E element){
//检查是否越界
rangeCheck(index); E oldValue = (E)values[index];
values[index] = element; return oldValue;
} /**
* 在数组的末尾增加一个元素
* @param element
*/
public void add(E element){
//扩容
ensureCapacity(size+);
values[size++] = element; } /**
* @param index
* @param element
*/
public void add(int index,E element){
//先检查数组的下标是否越界了
rangeCheck(index);
//扩容
ensureCapacity(size+); Object[] oldValues = values;
values[index] = element; //将原数组index后的值拷贝带新数组中
System.arraycopy(oldValues, index, values, index+, size-index); size++; } /**
* 将一个collection中的元素添加到数组末尾
* @param c
*/
public void addAll(Collection c){
Object[] cArray = c.toArray(); //扩容
ensureCapacity(size+cArray.length); //将传入数据拷贝到数组末尾
System.arraycopy(cArray, , values, size, cArray.length); size += cArray.length;
} /**
* 将一个collection中的元素添加到数组的指定位置
* @param index
* @param c
*/
public void addAll(int index,Collection c){
//先检查数组的下标是否越界了
rangeCheck(index);
//扩容
Object[] cArray = c.toArray();
int cLength = cArray.length; ensureCapacity(size+cLength); Object[] oldValues = values;
//将传入数据拷贝到数组指定位置
System.arraycopy(cArray, , values, index, cLength); //将原数组中index以后的数据拷贝过来
System.arraycopy(oldValues, index, values, values.length-, size-index); size += cLength; } /**
* 根据下标获取元素
* @param index
* @return
*/
public E get(int index){
//先检查数组的下标是否越界了
rangeCheck(index); E e = (E) values[index]; return e; } /**
* 根据下标删除元素
* @param index
* @return
*/
public E remove(int index){
//先检查数组的下标是否越界了
rangeCheck(index); E removeValue = (E) values[index]; System.arraycopy(values, index+, values, index, size-index-); //置为空,gc回收
values[size--] = null; return removeValue; } /**
* 根据对象删除
* @param o
*/
public void remove(Object o){
//考虑元素为null的情况
if(null == o){
for (int i = ; i < size; i++) {
if(values[i] == null){
remove(i);
}
} }else{
for (int i = ; i < size; i++) {
if(values[i].equals(o)){
remove(i);
}
} }
} /**
* 扩容方法,保证数组的长度足够
* @param minCapacity
*/
public void ensureCapacity(int minCapacity){
modCount++; int oldCapacity = values.length;
if (minCapacity > oldCapacity) {
//先默认扩容50%+1,如果还是不能满足,则直接用传入的所需容量
int newCapacity = (oldCapacity*)/+;
if(newCapacity < minCapacity){
newCapacity = minCapacity;
} values = Arrays.copyOf(values, newCapacity); }
} public int size(){
return size;
} }

最后再介绍一下ensureCapacity这个方法的想法(从网上看到的):

我们知道ArrayList的内部是采用数组来存储元素的,由于java数组都是定长的,所以这个数组的大小一定是固定的,这个大小就是capacity。我们可以肯定capacity一定是大于或等于ArrayList的size,那么当size不断增加到了要超过capacity的时候,ArrayList就不得不重新创建新的capacity来容纳更多的元素,这时需要首先建立一个更长的数组,将原来的数组中的元素复制到新数组中,再删除原来的数组。可见当ArrayList越来越大时,这种操作的消耗也是越来越大的。
为了减少这种不必要的重建capacity的操作,当我们能肯定ArrayList大致有多大(或者至少会有多大)时,我们可以先让ArrayList把capacity设为我们期望的大小,以避免多余的数组重建。
假设ArrayList自动把capacity设为10,每次重建时将长度递增原来的三分之二,那么当我们需要大约存储50个元素到ArrayList中时,就会大约需要重建数组4次,分别是在增加第11、第17、第26、第39个元素的时候进行的。如果我们一开始就让ArrayList的capacity为50,那么不需要任何数组重建就能完成所有插入操作了。
java允许我们在构造ArrayList的同时指定capacity,如new ArrayList(50),也允许在以后将它设得更大,而增大capacity就是使用ensureCapacity()方法。注意:capacity只能比原来的更大,而不能比原来的更小,否则java会忽略该操作。ArrayList的初始默认capacity为10,所以给capacity指定小于10的整数是毫无意义的。
最后说说ArrayList的size,前面说过,size一定小于等于capactiy,而且更重要的是,访问超过size的位置将抛出异常,尽管这个位置可能没有超过capacity。ensureCapacity()只可能增加capacity,而不会对size有任何影响。要增加size,只能用add()方法。

Java ArrayList的模拟实现的更多相关文章

  1. Mockito:一个强大的用于Java开发的模拟测试框架

    https://blog.csdn.net/zhoudaxia/article/details/33056093 介绍 本文将介绍模拟测试框架Mockito的一些基础概念, 介绍该框架的优点,讲解应用 ...

  2. java.net.URL 模拟用户登录网页并维持session

    java.net.URL 模拟用户登录网页并维持session 半成品,并非完全有用 import java.io.BufferedReader; import java.io.InputStream ...

  3. Java ArrayList、Vector和LinkedList等的差别与用法(转)

    Java ArrayList.Vector和LinkedList等的差别与用法(转) ArrayList 和Vector是采取数组体式格式存储数据,此数组元素数大于实际存储的数据以便增长和插入元素,都 ...

  4. 浅析 java ArrayList

    浅析 java ArrayList 简介 容器是java提供的一些列的数据结构,也可以叫语法糖.容器就是用来装在其他类型数据的数据结构. ArrayList是数组列表所以他继承了数组的优缺点.同时他也 ...

  5. java.net.URL 模拟用户登录网页并维持session【转】

    java.net.URL 模拟用户登录网页并维持session 半成品,并非完全有用 import java.io.BufferedReader; import java.io.InputStream ...

  6. Java ArrayList中对象的排序 (Comparable VS Comparator)

    我们通常使用Collections.sort()方法来对一个简单的数据列表排序.但是当ArrayList是由自定义对象组成的,就需要使用comparable或者comparator接口了.在使用这两者 ...

  7. Java ArrayList源码剖析

    转自: Java ArrayList源码剖析 总体介绍 ArrayList实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现.除该类未实现同步外 ...

  8. Java ArrayList 源代码分析

    Java ArrayList 之前曾经参考 数据结构与算法这本书写过ArrayList的demo,本来以为实现起来都差不多,今天抽空看了下jdk中的ArrayList的实现,差距还是很大啊 首先看一下 ...

  9. Java ArrayList trimToSize()

    前几天看了Java ArrayList,没有明白trimToSize()这个方法是什么意思,所以看了一下源码并且debug一下自己的一个例子,明白了其中的含义.贴在这里. ArrayList al = ...

随机推荐

  1. Python Requests 小技巧总结

    关于 Python Requests ,在使用中,总结了一些小技巧把,分享下. 1:保持请求之间的Cookies,我们可以这样做. import requests self.session = req ...

  2. java字节流和字符流编码格式(转自姚刚)

    /** * 字节流和字符流的区别, * (1)字符流带有缓冲,必须flush或close后数据才会从缓存中写入磁盘文件. * 字节流直接写文件. * (2)字符流在创建流的时候,指定编码,字节流在文件 ...

  3. 【转】Spring Bean属性解析

    转载自:http://wenku.baidu.com/view/30c7672cb4daa58da0114ae2.html Bean所以属性一览: <bean id="beanId&q ...

  4. [ Python - 4 ] python 装饰器

    装饰器有很多经典的使用场景,例如插入日志.性能测试.事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的. 装饰器有两种写法: 1. 装饰器不传参数 2. 装 ...

  5. Hibernate 和 Mybatis的区别

    第一方面:开发速度的对比 就开发速度而言,Hibernate的真正掌握要比Mybatis来得难些.Mybatis框架相对简单很容易上手,但也相对简陋些.个人觉得要用好Mybatis还是首先要先理解好H ...

  6. 项目问题整理(it)

    1,很(屎)优(一)雅(样)的IE9兼容问题: --webuploader在webkit浏览器中自动使用h5上传,但在IE中需要配置支持flash,特别注意两点: ①Upload.swf路径问题不正确 ...

  7. js排序(转载)

    原文地址:http://blog.csdn.net/wzwlln/article/details/6187732#plain sort(sortfunction)为javascript的数组对象(Ar ...

  8. tushare 安装

    1.pip install lxml 2.pip install pandas 3.pip install requests 4.pip install lxml 5.pip install tush ...

  9. python 多进程并发与多线程并发

    本文对python支持的几种并发方式进行简单的总结. Python支持的并发分为多线程并发与多进程并发(异步IO本文不涉及).概念上来说,多进程并发即运行多个独立的程序,优势在于并发处理的任务都由操作 ...

  10. 使用Mybatis做批量插入

    最近有个需求,将excel的数据导入的数据库的这个一个操作. 工作主要分为:解析excel,将excel中的数据单条循环插入数据库. 使用框架:mybatis+spring 使用过Mybatis的人都 ...