zoukankan      html  css  js  c++  java
  • JAVA容器-模拟ArrayList的底层实现

    概述

      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());
        }
    
    }
    

    }

  • 相关阅读:
    实习的一些感想,感触,心得体会
    一张优惠券引发的血案(redis并发安全问题)
    Java各种对象(PO,BO,VO,DTO,POJO,DAO,Entity,JavaBean,JavaBeans)的区分
    Redis 集群
    Maven Pom文件标签详解
    Google Guava 基本工具
    context:component-scan的使用说明
    logback的简单分析
    轮询和长轮询
    StringUtils中 isNotEmpty 和isNotBlank的区别?
  • 原文地址:https://www.cnblogs.com/qiuyong/p/6561132.html
Copyright © 2011-2022 走看看