手写ArryList简易版

本文作者为了深入理解ArrayList,手写了一个简易版的ArrayList,并详细介绍了ArrayList的底层实现原理,包括数组拷贝的方法如Arrays.copyOf和System.arraycopy。此外,文章还对比了ArrayList与Vector的区别,指出Vector是线程安全但效率较低,而ArrayList在非线程安全环境下性能更优。

手写ArryList简易版

为了加深自己对ArryList集合数据结构的理解,参考一些资料手写了一个简易版的ArryList集合,将自己的容易遗漏的知识点记录下来,方便以后自己回顾。

java运算符介绍

<<:左移运算符,num << 1,相当于num乘以2
>>:右移运算符,num >> 1,相当于num除以2
>>>:无符号右移,忽略符号位,空位都以0补齐

数组拷贝

Arrays.copyOf功能是实现数组的复制,返回复制后的数组。参数是被复制的数组和复制的长度
System.arraycopy System.arraycopy方法:如果是数组比较大,那么使用System.arraycopy会比较有优势,因为其使用的是内存复制,省去了大量的数组寻址访问等时间
复制指定源数组src到目标数组dest。复制从src的srcPos索引开始,复制的个数是length,复制到dest的索引从destPos开始。

src:源数组; srcPos:源数组要复制的起始位置;
dest:目的数组; destPos:目的数组放置的起始位置;length:复制的长度。
注意:src and dest都必须是同类型或者可以进行转换类型的数组.
有趣的是这个函数可以实现自己到自己复制,比如:
int[] fun ={0,1,2,3,4,5,6};
System.arraycopy(fun,0,fun,3,3);
则结果为:{0,1,2,0,1,2,6};
实现过程是这样的,先生成一个长度为length的临时数组,将fun数组中srcPos
到srcPos+length-1之间的数据拷贝到临时数组中,再执行System.arraycopy(临时数组,0,fun,3,3).

List 集合介绍

List集合代表一个有序集合,集合中每个元素都有其对应的顺序索引。List集合允许使用重复元素,可以通过索引来访问指定位置的集合元素。

List接口继承于Collection接口,它可以定义一个允许重复的有序集合。因为List中的元素是有序的,所以我们可以通过使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。

List接口为Collection直接接口。List所代表的是有序的Collection,即它用某种特定的插入顺序来维护元素顺序。用户可以对列表中每个元素的插入位置进行精确地控制,同时可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。实现List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。

ArrayList底层实现原理

1、自定义list接口

package com.zzw.list;

/**
 * @author zzw
 * @version 1.0
 * @description 自定义list接口
 * @modifiedBy
 */
public interface ExtList<E> {

    void add(E e);

    void add(int index, E e);

    E remove(int index);

    boolean remove(Object e);

    int getSize();

    E get(int index);
}


  1. 自定义实现ArrayList集合
package com.zzw.list;

import javax.swing.text.StyledEditorKit;
import javax.xml.ws.soap.Addressing;
import java.util.Arrays;


/**
 * @author zzw
 * @version 1.0
 * @description 自定义实现ArrayList集合
 * @modifiedBy
 */
public class ExtArrayList<E> implements ExtList<E> {

    // 保存ArrayList中数据的数组
    private transient Object[] elementData;
    // ArrayList实际数量
    private int size;

    public ExtArrayList() {
        this(10);
    }

    public ExtArrayList(int initCapacity) {
        if (initCapacity < 0) {
            throw new IllegalArgumentException("Illegal Capacity: " + initCapacity);
        }
        //初始化数组容量
        elementData = new Object[initCapacity];
    }

    public void add(E e) {
        //1、检查数组是否需要扩容
        ensureExplicitCapacity(size + 1);
        //2、添加新数组
        elementData[size++] = e;
    }

    public void add(int index, E e) {
        //1、检查数组是否越界
        rangeCheck(index);
        //2、检查数组是否需要扩容
        ensureExplicitCapacity(size + 1);
        //3、将从index+1下标的数组,向后移位,需要移动数组长度size-index
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
        //4、保存index下标的新元素
        elementData[index] = e;
        //5、数组长度++
        size++;
    }

    public E remove(int index) {
        //1、取出数组值
        E e = (E) elementData[index];
        //2、检查需要移动的数组的长度
        int numMoved = elementData.length - index - 1;
        if (numMoved > 0) {
            System.arraycopy(elementData, index + 1, elementData, index, numMoved);
            //3、将删除的数组设置为null
            elementData[--size] = null;
        }
        return e;
    }

    public boolean remove(E e) {
        for (int i = 0; i < elementData.length; i++) {
            E element = (E) elementData[i];
            if (element.equals(e)) {
                remove(i);
                return true;
            }

        }
        return false;
    }

    public int getSize() {
        return size;
    }

    public E get(int index) {
        //检验数组是否越界
        rangeCheck(index);
        E e = (E) elementData[index];
        return e;
    }

    /*
     * @author zzw
     * @description 检查数组是否需要扩容
     * @params 初始容量
     * @return
     **/
    private void ensureExplicitCapacity(int minCapacity) {
        // 如果存入的数据,超出了默认数组初始容量 就开始实现扩容
        if (size == elementData.length) {
            // 获取原来数组的长度 2
            int oldCapacity = elementData.length;
            // oldCapacity >> 1 理解成 oldCapacity/2 新数组的长度是原来长度1.5倍
            int newCapacity = oldCapacity + (oldCapacity >> 1); // 3
            if (newCapacity < minCapacity) {
                // 最小容量比新容量要小的,则采用初始容量minCapacity
                newCapacity = minCapacity;
            }
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
    }

    /*
     * @author zzw
     * @description 检查数组是否越界方法
     * @params
     * @return
     **/
    private void rangeCheck(int index) {
        if (index >= size) {
            throw new IndexOutOfBoundsException("数组越界啦!");
        }
    }
}



  1. 集合测试类
package com.zzw.list;
/**
 * @author zzw
 * @version 1.0
 * @description 测试类
 * @modifiedBy
 */
public class Test {

    public static void main(String[] args) {
        ExtList<String> extArrayList = new ExtArrayList<String>();
        extArrayList.add("张三");
        extArrayList.add("李四");
        extArrayList.add("王五");
        extArrayList.add(0, "周六");
        print(extArrayList);
//        System.out.println("获取第五个元素值:" + extArrayList.get(4));
        System.out.println("-------移除元素--------------");
        extArrayList.remove("张三");
        print(extArrayList);

    }
    public static  void print(ExtList lis){
        for(int i = 0 ; i < lis.getSize();i++){
            System.out.println("获取第"+(i+1)+"个元素值:" + lis.get(i));
        }
    }
}

4、运行结果

获取第1个元素值:周六
获取第2个元素值:张三
获取第3个元素值:李四
获取第4个元素值:王五
-------移除元素--------------
获取第1个元素值:周六
获取第2个元素值:李四
获取第3个元素值:王五

Vector与ArrayList集合的区别

Vector是线程安全的,但是性能比ArrayList要低。
ArrayList,Vector主要区别为以下几点:
1、Vector是线程安全的,源码中有很多的synchronized可以看出,而ArrayList不是。导致Vector效率无法和ArrayList相比;
2、ArrayList和Vector都采用线性连续存储空间,当存储空间不足的时候,ArrayList默认增加为原来的50%,Vector默认增加为原来的一倍;
3、Vector可以设置capacityIncrement,而ArrayList不可以,从字面理解就是capacity容量,Increment增加,容量增长的参数。

	 private void grow(int minCapacity) {  
	        // overflow-conscious code  
	        int oldCapacity = elementData.length;  
	        int newCapacity = oldCapacity + (oldCapacity >> 1); //扩充的空间增加原来的50%(即是原来的1.5倍)  
	        if (newCapacity - minCapacity < 0) //如果容器扩容之后还是不够,那么干脆直接将minCapacity设为容器的大小  
	            newCapacity = minCapacity;  
	        if (newCapacity - MAX_ARRAY_SIZE > 0) //如果扩充的容器太大了的话,那么就执行hugeCapacity  
	            newCapacity = hugeCapacity(minCapacity);  
	        // minCapacity is usually close to size, so this is a win:  
	        elementData = Arrays.copyOf(elementData, newCapacity);  
	    }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值