概述

  ArrayList实质上就是可变数组的实现,着重理解:add、get、set、remove、iterator的实现,我们将关注一下问题。

  1、创建ArrayList的时候,默认给数组的长度设置为10。

  2、当set、remove、set的时候,如何解决越界问题?

  3、当add的时候,如何解决扩容问题?

  4、由于数组是不可变的时候,我们需要频繁重新新建数组重新赋值。

模拟实现

1、ArrayList定义变量与初始化。

//定义存储数据的数组
private transient Object [] elementData;
//容量大小
private int size;
//默认构造器设置数组长度为10
public MyArrayList() {
this(10);
}
</span><span style="color: #0000ff;">public</span> MyArrayList(<span style="color: #0000ff;">int</span><span style="color: #000000;"> capacity)  {
</span><span style="color: #0000ff;">super</span><span style="color: #000000;">();
</span><span style="color: #0000ff;">if</span>(capacity&lt;0<span style="color: #000000;">){
</span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> IllegalArgumentException("数字不能小于0"<span style="color: #000000;">);
}
elementData</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> Object[capacity];
}</span></pre>

2、解决越界问题:当索引值小于0或者索引值大于等于size就将越界。

 public void rangeCheck(int index){
if(index<0 ||index>this.size){
throw new IndexOutOfBoundsException("越界"+index);
}
}

3、解决扩容问题:普通扩容(new=old+old*2)、索引值依然大于普通扩容(new=index)、当超过int的取值范围(int的最大范围-8)

 public void ensureCapacity(int minCapacity){
if(minCapacity>elementData.length){
//获得初始容器大小
int oldCapacity=elementData.length;
//新的容器大小:初始容器大小+2初始容器大小(不懂为啥这样加)
int newCapacity=oldCapacity+(oldCapacity>>1);
//当新增以后,还不能满足索引长度,即将数组设置为最小索引长度
if(newCapacity<minCapacity){
newCapacity=minCapacity;
}
//当超过int的范围的时候
if(minCapacity>Integer.MAX_VALUE-8){
newCapacity=Integer.MAX_VALUE-8;
}
Object [] elments=new Object[newCapacity];
//创建新的数组重新赋值。
System.arraycopy(elementData,0,elments,0,size);
elementData=elments;
}
}

4、谈谈迭代器:hasNext():判断是否有下一个、next():当前游标指向的值、remove():删除刚变过过的元素;

   private class Iter implements Iterator{
//游标
private int cursor=0;
//指向刚遍历过的元素
private int lastRet=0;
public boolean hasNext() {
return size!=cursor;
}
    </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Object next() {
</span><span style="color: #0000ff;">int</span> i =<span style="color: #000000;">cursor;
</span><span style="color: #0000ff;">if</span>(i&gt;=<span style="color: #000000;">size){
</span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> NoSuchElementException();
}
cursor</span>=i+1<span style="color: #000000;">;
</span><span style="color: #0000ff;">return</span> elementData[lastRet=<span style="color: #000000;">i];
} </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> remove() {
</span><span style="color: #0000ff;">if</span>(cursor&lt;0<span style="color: #000000;">){
</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> IllegalThreadStateException();
}
MyArrayList.</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.remove(cursor);
cursor</span>=<span style="color: #000000;">lastRet;
</span><span style="color: #008000;">//</span><span style="color: #008000;">当删除一个元素的时候,赋值为0</span>
lastRet=-1<span style="color: #000000;">;
}
}</span></pre>

5、我相信乐忠于理解源码的同学的基础,弄清楚以上问题,应该ArrayList就没有问题了。

public class MyArrayList<E>  {
//定义存储数据的数组
private transient Object [] elementData;
//容量大小
private int size;
//默认构造器设置数组长度为10
public MyArrayList() {
this(10);
}
</span><span style="color: #0000ff;">public</span> MyArrayList(<span style="color: #0000ff;">int</span><span style="color: #000000;"> capacity)  {
</span><span style="color: #0000ff;">super</span><span style="color: #000000;">();
</span><span style="color: #0000ff;">if</span>(capacity&lt;0<span style="color: #000000;">){
</span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> IllegalArgumentException("数字不能小于0"<span style="color: #000000;">);
}
elementData</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> Object[capacity];
} </span><span style="color: #0000ff;">public</span> E get(<span style="color: #0000ff;">int</span><span style="color: #000000;"> index) {
rangeCheck(index);
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> (E) elementData[index];
} </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> set(<span style="color: #0000ff;">int</span><span style="color: #000000;"> index, E element) {
rangeCheck(index);
ensureCapacity(index</span>+1<span style="color: #000000;">);
E oldVlue</span>=<span style="color: #000000;"> (E) elementData[index];
</span><span style="color: #0000ff;">this</span>.elementData[index]=<span style="color: #000000;">element;
} </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> add(E e) {
ensureCapacity(size</span>+1<span style="color: #000000;">);
elementData[size]</span>=<span style="color: #000000;">e;
size</span>++<span style="color: #000000;">;
} </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> add(<span style="color: #0000ff;">int</span><span style="color: #000000;"> index, E element) {
rangeCheck(index);
ensureCapacity(index</span>+1<span style="color: #000000;">);
</span><span style="color: #008000;">//</span><span style="color: #008000;">动态数组</span>
System.arraycopy(elementData,index,elementData,index+1,size-<span style="color: #000000;">index);
elementData[index]</span>=<span style="color: #000000;">element;
size</span>++<span style="color: #000000;">;
} </span><span style="color: #008000;">//</span><span style="color: #008000;">移除</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> remove(<span style="color: #0000ff;">int</span><span style="color: #000000;"> index) {
rangeCheck(index);
E oldVlue</span>=<span style="color: #000000;"> (E) elementData[index];
</span><span style="color: #0000ff;">int</span> moved=size-index-1<span style="color: #000000;">;
</span><span style="color: #0000ff;">if</span>(moved&gt;0<span style="color: #000000;">)
System.arraycopy(elementData,index</span>+1,elementData,index,size-<span style="color: #000000;">index);<br />    elementData[--size]=null;
} </span><span style="color: #008000;">//</span><span style="color: #008000;">判断是否越界</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> rangeCheck(<span style="color: #0000ff;">int</span><span style="color: #000000;"> index){
</span><span style="color: #0000ff;">if</span>(index&lt;0 ||index&gt;<span style="color: #0000ff;">this</span><span style="color: #000000;">.size){
</span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> IndexOutOfBoundsException("越界"+<span style="color: #000000;">index);
}
} </span><span style="color: #008000;">//</span><span style="color: #008000;">扩容</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> ensureCapacity(<span style="color: #0000ff;">int</span><span style="color: #000000;"> minCapacity){
</span><span style="color: #0000ff;">if</span>(minCapacity&gt;<span style="color: #000000;">elementData.length){
</span><span style="color: #008000;">//</span><span style="color: #008000;">获得初始容器大小</span>
<span style="color: #0000ff;">int</span> oldCapacity=<span style="color: #000000;">elementData.length;
</span><span style="color: #008000;">//</span><span style="color: #008000;">新的容器大小:初始容器大小+2初始容器大小(不懂为啥这样加)</span>
<span style="color: #0000ff;">int</span> newCapacity=oldCapacity+(oldCapacity&gt;&gt;1<span style="color: #000000;">);
</span><span style="color: #008000;">//</span><span style="color: #008000;">当新增以后,还不能满足索引长度,即将数组设置为最小索引长度</span>
<span style="color: #0000ff;">if</span>(newCapacity&lt;<span style="color: #000000;">minCapacity){
newCapacity</span>=<span style="color: #000000;">minCapacity;
}
</span><span style="color: #008000;">//</span><span style="color: #008000;">当超过int的范围的时候</span>
<span style="color: #0000ff;">if</span>(minCapacity&gt;Integer.MAX_VALUE-8<span style="color: #000000;">){
newCapacity</span>=Integer.MAX_VALUE-8<span style="color: #000000;">;
}
Object [] elments</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> Object[newCapacity];
</span><span style="color: #008000;">//</span><span style="color: #008000;">创建新的数组重新赋值。</span>
System.arraycopy(elementData,0,elments,0<span style="color: #000000;">,size);
elementData</span>=<span style="color: #000000;">elments;
}
} </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> size(){
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> size;
} </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Iterator iterator(){
</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> Iter();
} </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">class</span> Iter <span style="color: #0000ff;">implements</span><span style="color: #000000;"> Iterator{
</span><span style="color: #008000;">//</span><span style="color: #008000;">游标</span>
<span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> cursor=0<span style="color: #000000;">;
</span><span style="color: #008000;">//</span><span style="color: #008000;">指向刚遍历过的元素</span>
<span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> lastRet=0<span style="color: #000000;">;
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">boolean</span><span style="color: #000000;"> hasNext() {
</span><span style="color: #0000ff;">return</span> size!=<span style="color: #000000;">cursor;
} </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Object next() {
</span><span style="color: #0000ff;">int</span> i =<span style="color: #000000;">cursor;
</span><span style="color: #0000ff;">if</span>(i&gt;=<span style="color: #000000;">size){
</span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> NoSuchElementException();
}
cursor</span>=i+1<span style="color: #000000;">;
</span><span style="color: #0000ff;">return</span> elementData[lastRet=<span style="color: #000000;">i];
} </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> remove() {
</span><span style="color: #0000ff;">if</span>(cursor&lt;0<span style="color: #000000;">){
</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> IllegalThreadStateException();
}
MyArrayList.</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.remove(cursor);
cursor</span>=<span style="color: #000000;">lastRet;
</span><span style="color: #008000;">//</span><span style="color: #008000;">当删除一个元素的时候,赋值为0</span>
lastRet=-1<span style="color: #000000;">;
}
} </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String [] args){
MyArrayList ls</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> MyArrayList();
ls.add(</span>123<span style="color: #000000;">);
ls.add(</span>123<span style="color: #000000;">);
ls.set(</span>0,456<span style="color: #000000;">);
ls.remove(</span>1<span style="color: #000000;">);
System.out.println(ls.size());
System.out.println(ls.get(</span>0<span style="color: #000000;">)); Iterator it</span>=<span style="color: #000000;">ls.iterator();
</span><span style="color: #0000ff;">while</span><span style="color: #000000;">(it.hasNext()){
System.out.println(it.next());
} }

}

JAVA容器-模拟ArrayList的底层实现的更多相关文章

  1. JAVA容器-模拟LinkedList实现(双链表)

    概述 LinkedList实质上就是双向链表的拓展的实现,我们将关注一下问题.LinkedList 1.双向链表怎么来实现插入.删除.查询? 2.利用二分法提高查询效率. 3.不同步,线程不安全,需要 ...

  2. 【Java心得总结五】Java容器上——容器初探

    在数学中我们有集合的概念,所谓的一个集合,就是将数个对象归类而分成为一个或数个形态各异的大小整体. 一般来讲,集合是具有某种特性的事物的整体,或是一些确认对象的汇集.构成集合的事物或对象称作元素或是成 ...

  3. 迭代器模式在 Java 容器中的实现

    迭代器接口是迭代器模式实现的精髓: public interface Iterator<E> { boolean hasNext(); E next(); ... } 假设某容器名为 Xx ...

  4. 理解java容器底层原理--手动实现ArrayList

    为了照顾初学者,我分几分版本发出来 版本一:基础版本 实现对象创建.元素添加.重新toString() 方法 package com.xzlf.collection; /** * 自定义一个Array ...

  5. Java 容器源码分析之 ArrayList

    概览 ArrayList是最常使用的集合类之一了.在JDK文档中对ArrayList的描述是:ArrayList是对list接口的一种基于可变数组的实现.ArrayList类的声明如下: 12 pub ...

  6. Java容器学习之ArrayList

    一.概述 ArrayList是java中十分常用的集合类,继承于AbstractList,并实现了List.RandomAccess.Cloneable和Serializable接口.ArrayLis ...

  7. Java容器源码解析之——ArrayList

    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess ...

  8. Java容器深入浅出之List、ListIterator和ArrayList

    List是Collection接口的子接口,表示的是一种有序的.可重复元素的集合. List接口的主要实现类ArrayList和Vector,底层都是维护了一套动态的,可扩展长度的Object[]数组 ...

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

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

随机推荐

  1. caffe Python API 之SoftmaxWithLoss

    net.loss = caffe.layers.SoftmaxWithLoss(net.fc3, net.label) 输出: layer { name: "loss" type: ...

  2. 004ICMP-type对应表

    一次在某个防火墙配置策略里看到如下的代码: iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT iptables -A FORWARD -p icmp ...

  3. Sklearn-GridSearchCV网格搜索

    GridSearchCV,它存在的意义就是自动调参,只要把参数输进去,就能给出最优化的结果和参数.但是这个方法适合于小数据集,一旦数据的量级上去了,很难得出结果.这个时候就是需要动脑筋了.数据量比较大 ...

  4. 【转】Python OCR识别图片验证码

    转载自:博客 对于某些网站登录的时候,往往需要输入验证码才能实现登录.如果要爬虫这类网站,往往总会比这个验证码导致无法爬取数据.以下介绍一种比较折中的方法,也是比较可行的方法: 实现思想: 1.通过截 ...

  5. 使用360对app安全进行加固

    在写了第一个app之后,打算上架到各个渠道看看,无意间看到了360的app加固工具 http://jiagu.360.cn/ 自己体验了一把,加固过程很傻瓜化, 加固好了之后,还要对app进行二次签名 ...

  6. Windows Azure 初体验

    最近看到windows azure 在做活动,只需花一块钱就可以体验一个月的windows azure. 于是,我就注册了一个账号也尝试一把云时代,传送门. 注册很简单的,成功后可以看到这个界面. 然 ...

  7. jvisualvm 远程连接jboss

    由于项目中使用jboss 作为web容器,每当项目上线时需要使用loadrunner对项目进行性能压测,这时就需要实时观察JVM的一些参数.想使用jvisualvm借助jstatd远程连接服务器上面的 ...

  8. 第七章:Mapping插件

    Mapping插件 Knockout设计成允许你使用任何JavaScript对象作为view model.必须view model的一些属性是observable的,你可以使用KO绑定他们到你的UI元 ...

  9. Saltstack 介绍、安装、配置语法(一)

    Slatstack 介绍 官网:https://saltstack.com/ 官方源:http://repo.saltstack.com/  (介绍各操作系统安装方法) yum install htt ...

  10. Java 中的静态嵌套类和非静态嵌套类

    Java 中的静态嵌套类和非静态嵌套类 术语:嵌套类分为两类:静态嵌套类和非静态嵌套类.声明 static 的嵌套类称为静态嵌套类,非静态嵌套类也称为内部类. class OuterClass { p ...