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. vue+axios下载文件的实现

    HTML代码: <el-button size="medium" @click="download">下载表格</el-button> ...

  2. [ 总结 ] vsftpd 虚拟用户配置

    需求:在不更改目录权限的前提下,ftp用户对目录里的文件拥有所有权. [root@server2 ~]# yum install vsftpd -y [root@server2 ~]# cd /etc ...

  3. discuz自定义生成单页面

    在pc端,若要生成一个单页面,有一个比较方便的方法是生成新的专题页,然后diy其中的内容. 不过这种做法有两个缺点 1 url太过冗赘 2 只有一个插入url代码功能,没有文本编辑功能 而且文本框小的 ...

  4. Spring boot 文件路径读取异常

    在开发代码中,有一段需要获取resources目录下的一个配置文件(这里写作test.xml). 这段代码在ide中没有任何问题,但是一打成jar包发布到线上,这段代码就会报找不到对应文件的错误. 按 ...

  5. 深入解析当下大热的前后端分离组件django-rest_framework系列一

    前言 Nodejs的逐渐成熟和日趋稳定,使得越来越多的公司开始尝试使用Nodejs来练一下手,尝一尝鲜.在传统的web应用开发中,大多数的程序员会将浏览器作为前后端的分界线.将浏览器中为用户进行页面展 ...

  6. pipreqs------查找python项目依赖并生成requirements.txt

    项目开发的时候,总是要搭建和部署环境,这时,就需要一个python第三方包的list,一般叫做requirements.txt.如果项目使用virtualenv环境,直接使用pip freeze即可, ...

  7. admin管理工具

    admin组件使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.你可以在项目的 settings.py 中的 INSTALLE ...

  8. JS监听页面滚动到底部事件

    废话不说,直接上代码,放心我这个是最好的,直接放到js脚本里,直接生效: $(window).scroll(function(){ var scrollTop = $(this).scrollTop( ...

  9. React Native - 1 Windows下的环境配置(Windows+Android)

    参考:https://facebook.github.io/react-native/docs/getting-started.html(要FQ)     网站上建议使用Chocolatey去配环境, ...

  10. [libGDX游戏开发教程]使用libGDX进行游戏开发(12)-Action动画

    前文章节列表:  使用libGDX进行游戏开发(11)-高级编程技巧   使用libGDX进行游戏开发(10)-音乐音效不求人,程序员也可以DIY   使用libGDX进行游戏开发(9)-场景过渡   ...