java 基于ArrayList底层源码分析并对常用功能进行代码实现

 

目录

ArrayList底层

原理

扩容

缩减

扩容和缩减需注意

System.arraycopy

说明

为什么要用?

我为什么不用?

Iterator迭代器

代码实现常用功能

首先定义了一个List接口,方法如下

List接口代码

ArrayList类代码

排序工具类代码,这里用的是快排


ArrayList底层

原理

ArrayList底层是一个Object数组,通过对数组的扩容和缩减,让使用者感觉到ArrayList是一个自动大小集合,用起来十分方便,解决了数组固定长度带来的不便。

扩容

Object数组的增长因子是20%,添加数据的时候,会根据Object数组实际保存数据长度size+要添加数据的长度是否大于当前Object数组实际的长度,如果大于说明需要扩容,因为当前数组已经存不下将要添加的数据了。

缩减

Object数组的缩减因子是50%,当移除数据时,发现Object数组实际保存数据的长度已小于或等于Object数组实际长度的50%,这个时候就会对Object数组进行,缩减操作,缩减到Object数组实际保存数据长度size的大小。为什么要缩减呢?不就是为了减少内存的开销,毕竟占着不用,太浪费资源了。

扩容和缩减需注意

扩容和缩减都会涉及到,要new一个新的Object数组,那么原来已存在的数组,不能置之不理。因为,原来的数组里面,每一个下标位置都还存放着指向对象的引用。一旦没有置NULL处理,假如当前Object数组要删除一些数据,删除后,当前Object数组,已经不再指向那些对象了,按理说那些对象要被当成垃圾,可是原有的数组没有把引用断掉,将导致已被当前object数组删除掉的对象不能及时被jvm当成垃圾,这样会造成内存被本该是垃圾的对象占用着,浪费系统资源。

System.arraycopy

jdk源代码

src:源数组

srcPos:源数组的下标位置(包含)

dest:目标数组

destPos:目标数组下标位置(包含)

length:源数组要移动数组长度

功能:将源数组下标位置srcPos至srcPos + length - 1之间下标的数据,移动到目标数组下标位置destPos至destPos + length - 1之间下标处,相当于整体把一个区间的数据,移动到另一个区间。

/*
* @param      src      the source array.
* @param      srcPos   starting position in the source array.
* @param      dest     the destination array.
* @param      destPos  starting position in the destination data.
* @param      length   the number of array elements to be copied
*/
public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

说明

ArrayList源码里面大量使用了这个方法,这个方法是native修饰本地方法,是c语写的,源码在jdk里面看不到。这个方法是对数组进行整体移动,jdk都大量使的方法,肯定是好东西,所以有需用到这个方法的也可以使用。

为什么要用?

因为数组自身的缺陷,在插入和删除操作时,需要对数组向前或向后整体移动,数据量太大时,这样必然在性能方面会下降很多,jdk为什么不用java代码写这个方法呢?肯定是嫌弃效率太底,所以才使用c语言写这个方法,供jdk调用。

我为什么不用?

本着写源码态度,所以用java代码自已写了arraycopy,因为我们知道arraycopy的逻辑处理,自然写起来也不难。

Iterator迭代器

通过继承Iterator接口,实现接口的方法,来实现一个迭代器。迭代器不就是为了方便我们对集合进行遍历,同时实现了迭代器还能用增强for去遍历。

代码实现常用功能

首先定义了一个List接口,方法如下

方法说明
int size();当前数组实际存储数据元素的个数
default boolean isEmpty() {
    return size() == 0;
}
接口默认实现,判断集合是否为空
default boolean contains(T t) {
    return -1 != indexOf(t);
}
接口默认实现,判断一个值是否包含在集合中
boolean contains(List<T> list);判断另一个集合,所有元素是否包含在当前集合中
int indexOf(T t);从头开始寻找,根据一个值,获取值对应的下标值
int lastIndexOf(T t);从尾部开始寻找,根据一个值,获取值对应的下标值
void add(T t);将一个值添加到当前集合
void add(int index, T t);将一个值,添加到集合中指定下标位置
void add(List<T> list);将另一个集合所有元素,添加到本集合中
void add(int index, List<T> list);将另一个集合所有元素,添加到本集合指定下标位置
T get(int index);根据下标位置获取一个值
T set(int index, T t);将集合指定下标位置值,替换为新值t
default void remove(T t) {
    remove(indexOf(t));
    trimToSize();
}
默认实现,将一个值从当前集合中移除
void remove(int index);将集合指定下标处值移除
void remove(List<T> list);将当前集合中包含list集合的值,移除
void remove(int fromIndex, int toIndex);将指定(包含)开始下标和(包含)结束下标之间值,从集合中移除
List<T> retain(List<T> list);当前集合中只保留list中存在的元素,相当于交集
List<T> subList(int fromIndex, int toIndex);获取一个子集合,根据(包含)开始下标位置和(包含)结束下标位置
void sort(Comparator<T> cmp);对集合进行排序
Object[] toArray();将集合转化成数组
void clear();清空集合
void trimToSize();缩减集合
int capacity();数组实际的长度

List接口代码

package com.wxl.practices.ArrayList;

import java.util.Comparator;

public interface List<T> extends Iterable<T> {

    int size();

    default boolean isEmpty() {
        return size() == 0;
    }

    default boolean contains(T t) {
        return -1 != indexOf(t);
    }

    boolean contains(List<T> list);

    int indexOf(T t);
    int lastIndexOf(T t);

    void add(T t);
    void add(int index, T t);
    void add(List<T> list);
    void add(int index, List<T> list);

    T get(int index);
    T set(int index, T t);

    default void remove(T t) {
        remove(indexOf(t));
        trimToSize();
    }
    void remove(int index);
    void remove(List<T> list);
    void remove(int fromIndex, int toIndex);

    List<T> retain(List<T> list);
    List<T> subList(int fromIndex, int toIndex);

    void sort(Comparator<T> cmp);
    Object[] toArray();

    void clear();
    void trimToSize();

    int capacity();
}

ArrayList类代码

package com.wxl.practices.ArrayList;

import java.util.Comparator;
import java.util.Iterator;

public class ArrayList<T> implements List<T> {
    //数组增长因子
    private final float INCREASE_FACTOR = 1.2f;
    //数组的缩减因子
    private final float DECREASE_FACTOR = 0.5f;
    //一个空数组
    private Object[] EMPTY = {};
    //一个临时数组,数组增长或缩减时交换值时用
    private Object[] temp = EMPTY;
    //保存值的数组
    private Object[] array;
    //数组实际存储数据的大小
    private int size;

    //创建ArrayList对象时给数组赋值为空数组
    public ArrayList() {
        this.array = EMPTY;
    }

    /**
     * 判断是否需要对数组时行扩容,如果需要则扩容,不需要不扩容
     * 增长因子是20%
     * @param needLength 当前数组要加入的元素
     */
    private void ensureCapacity(int needLength) {
        if (size + needLength > array.length) {
            changeArray((int) Math.ceil((size + needLength) * INCREASE_FACTOR));
        }
    }

    /**
     * 当前数组实际存储数据的个数
     * @return
     */
    @Override
    public int size() {
        return size;
    }

    /**
     * 判断List集合是否全部包含在当前集合
     * 如果全部包含则返回true
     * 只要有一个不包含就返回false
     * @param list
     * @return
     */
    @Override
    public boolean contains(List<T> list) {
        Iterator<T> it = list.iterator();
        while (it.hasNext()) {
            if(!contains(it.next())) {
                return false;
            }
        }
        return true;
    }

    /**
     * 根据值,查找值所在的下标
     * @param t 值
     * @param isForward 是否从前向后遍历true为从前向后,false为从后向前
     * @return
     */
    private int getIndex(T t, boolean isForward) {
        InnerIterator it = new InnerIterator(isForward);
        while (it.hasNext()) {
            if(it.next().equals(t)) {
                return it.getIndex();
            }
        }
        return -1;
    }

    /**
     * 从前向后查找集合中第一个和t相同的下标
     * @param t
     * @return
     */
    @Override
    public int indexOf(T t) {
        return getIndex(t, true);
    }

    /**
     * 从后向前查找集合中第一个和t相同的下标
     * @param t
     * @return
     */
    @Override
    public int lastIndexOf(T t) {
        return getIndex(t, false);
    }

    /**
     * 将t值添加到集合
     * @param t
     */
    @Override
    public void add(T t) {
        ensureCapacity(1);
        array[size++] = t;
    }

    /**
     * 将t值插入到指定的下标处
     * @param index
     * @param t
     */
    @Override
    public void add(int index, T t) {
        checkIndex(index);
        ensureCapacity(1);
        arraycopy(array, index, array, index + 1, size - index);
        array[index] = t;
        size++;
    }

    /**
     * 向集合中添加另一个集合
     * @param list
     */
    @Override
    public void add(List<T> list) {
        final int LEN = list.size();
        ensureCapacity(LEN);
        arraycopy(list.toArray(), 0, array, size, LEN);
        size += LEN;
    }

    /**
     * 在集合指定下标处添加另一个集合
     * @param index
     * @param list
     */
    @Override
    public void add(int index, List<T> list) {
        checkIndex(index);
        final int LEN = list.size();
        ensureCapacity(LEN);
        arraycopy(array, index, array, index + LEN, size - index);
        arraycopy(list.toArray(), 0, array, index, LEN);
        size += LEN;
    }

    /**
     * 获取指定下标的值
     * @param index
     * @return
     */
    @Override
    public T get(int index) {
        checkIndex(index);
        return (T) array[index];
    }

    /**
     * 将集合中指定下标的值添换为新t
     * @param index
     * @param t
     * @return
     */
    @Override
    public T set(int index, T t) {
        checkIndex(index);
        T oldT = (T) array[index];
        array[index] = t;
        return oldT;
    }

    /**
     * 将集合指定下标元素删除掉
     * @param index
     */
    @Override
    public void remove(int index) {
        checkIndex(index);
        arraycopy(array, index + 1, array, index, size - index - 1);
        array[--size] = null;
        trimToSize();
    }

    /**
     * 删除值当前集合中包含list的值,或不包含list的值,根据isContainsd确定
     * @param list
     * @param isContains
     * @return
     */
    private List<T> remove(List<T> list, boolean isContains) {
        List<T> rstList = null;
        if (!isContains) rstList = new ArrayList<>();
        Iterator<T> it = new InnerIterator<T>(true);
        T t;
        while (it.hasNext()) {
            t = it.next();
            if((isContains ? list.contains(t) : !list.contains(t))) {
                if (!isContains) rstList.add(t);
                it.remove();
            }
        }
        trimToSize();
        return rstList;
    }

    /**
     * 从当前集合中,删除当前集合包含list集合里面元素的值
     * @param list
     */
    @Override
    public void remove(List<T> list) {
        remove(list, true);
    }

    /**
     * 从当前集合中删除,指定下标开始(包含)和结束(包含)位置的元素
     * @param fromIndex
     * @param toIndex
     */
    @Override
    public void remove(int fromIndex, int toIndex) {
        checkIndex(fromIndex, toIndex);
        final int LEN = toIndex - fromIndex + 1;
        final int REMOVE_LEN = size - toIndex - 1;
        arraycopy(array, toIndex + 1, array, fromIndex, REMOVE_LEN);
        for (int i = fromIndex + REMOVE_LEN; i < size; i++) {
            array[i] = null;
        }
        size -= LEN;
        trimToSize();
    }

    /**
     * 当前集合中只保留list里面的元素,不包含在list里面的元素全部删除
     * @param list
     * @return
     */
    @Override
    public List<T> retain(List<T> list) {
        return remove(list, false);
    }

    /**
     * 获取指定开始(包含)和结束(包含)下标的元素
     * @param fromIndex
     * @param toIndex
     * @return
     */
    @Override
    public List<T> subList(int fromIndex, int toIndex) {
        checkIndex(fromIndex, toIndex);
        List<T> list = new ArrayList<>();
        for (int i = fromIndex; i <= toIndex; i++) {
            list.add((T) array[i]);
        }
        return list;
    }

    /**
     * 对集合进行排序
     * @param cmp
     */
    @Override
    public void sort(Comparator<T> cmp) {
        SortUtil.quickSort((T[]) array, 0, size - 1, cmp);
    }

    /**
     * 将集合转化成数组
     * @return
     */
    @Override
    public Object[] toArray() {
        Object[] rstObj = new Object[size];
        arraycopy(array, 0, rstObj, 0, size);
        return rstObj;
    }

    /**
     * 清空集合
     */
    @Override
    public void clear() {
        release(array);
        array = EMPTY;
        size = 0;
    }

    /**
     * 数组扩容或缩减时操作
     * @param len
     */
    private void changeArray(int len) {
        temp = array;
        array = new Object[len];
        arraycopy(temp, 0, array, 0, size);
        release(temp);
        temp = EMPTY;
    }

    /**
     * 数组缩减
     */
    @Override
    public void trimToSize() {
        if (size <= array.length * DECREASE_FACTOR) {
            changeArray(size);
        }
    }

    /**
     * 数组当前实际长度
     * @return
     */
    @Override
    public int capacity() {
        return array.length;
    }

    /**
     * 迭代器
     * @return
     */
    @Override
    public Iterator<T> iterator() {
        return new InnerIterator<>(true);
    }

    /**
     * 实现Iterator接口,写一个ArrayList的迭代器
     * @param <T>
     */
    private class InnerIterator<T> implements Iterator<T> {
        //是否从前向后 true
        private boolean isForward;
        //数组下标
        private int index;

        public InnerIterator(boolean isForward) {
            this.isForward = isForward;
            this.index = isForward ? 0 : size - 1;
        }

        @Override
        public boolean hasNext() {
            return isForward ? index < size : index >= 0;
        }

        @Override
        public T next() {
            return (T) (isForward ? array[index++] : array[index--]);
        }

        /**
         * 删除操作
         */
        @Override
        public void remove() {
            arraycopy(array, (isForward ? index : index + 2), array, (isForward ? index - 1 : index + 1),
                    (isForward ? size - index : size - (index + 2)));
            array[--size] = null;
            index += isForward ? -1 : 1;
        }

        /**
         * 获取下标
         * @return
         */
        public int getIndex() {
            return isForward ? index - 1 : index + 1;
        }
    }

    /**
     * 实现System.arraycopy本地方法
     * 将一个数组元素拷贝到另一个数组
     *public static native void arraycopy(Object src,  int  srcPos,
     *                                         Object dest, int destPos,
     *                                         int length);
     * @param src 源数组
     * @param srcPos 源数组下标位置
     * @param dest 目标数组
     * @param destPos 目标数组的下标位置
     * @param length 源数组要拷贝的长度
     */
    private void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) {
        Object[] newSrc = null;
        if(src == dest) {
            newSrc = new Object[size];
            for (int i = 0; i < size; i++) {
                newSrc[i] = src[i];
            }
        }
        for (int i = srcPos; i < srcPos + length; i++) {
            dest[destPos++] = (src == dest ? newSrc[i] : src[i]);
        }
    }

    /**
     * 释放数组指向引用,为的防止,某个对象被删除以后,还有引用指向它,虽然是垃圾
     * 但是,因为有引用指向它,不能被及时回收
     * @param relObj
     */
    private void release(Object[] relObj) {
        for (int i = 0; i < size; i++) {
            relObj[i] = null;
        }
    }

    /**
     * 下标值判断
     * @param index
     * @param name
     */
    private void checkIndex(int index, String...name) {
        if (index >= size || index < 0) {
            throw new IndexOutOfBoundsException((name.length > 0 ? name[0] : "index") + "下标输入错误,输入下标为:" +
                    index + ",当前集合下标范围为0~" + (size - 1) + "。");
        }
    }

    /**
     * 下标值判断
     * @param fromIndex
     * @param toIndex
     */
    private void checkIndex(int fromIndex, int toIndex) {
        if (toIndex < fromIndex) {
            throw new RuntimeException("toIndex值为:" + toIndex + "小于fromIndex值为:" + fromIndex);
        }
        checkIndex(fromIndex, "fromIndex");
        checkIndex(toIndex, "toIndex");
    }
}

排序工具类代码,这里用的是快排

package com.wxl.practices.ArrayList;

import java.util.Comparator;

/**
 * 此排序专门为List调用,无法单独调用,因为此处需要泛型数组
 * 因此调用者需要是一个泛型
 * 因为List本来就是一个泛型集合,因此可以调用
 */

public class SortUtil {
    /**
     * 排序值交换方法
     * @param array 数组
     * @param fromIndex 要交换值的数组下标
     * @param toIndex 要交换值的数组下标
     * @param <T> 泛型
     */
    private static <T> void swap(T[] array, int fromIndex, int toIndex) {
        T temp = array[fromIndex];
        array[fromIndex] = array[toIndex];
        array[toIndex] = temp;
    }

    /**
     * 获取中位数的下标
     * @param array 数组
     * @param beginIndex 开始索引
     * @param endIndex 结束索引
     * @param cmp 比较器
     * @param <T>
     * @return
     */
    private static <T> int getMidIndex(T[] array, int beginIndex, int endIndex, Comparator<T> cmp) {
        int oldBeginIndex = beginIndex;
        while (beginIndex < endIndex) {
            while (beginIndex < endIndex && cmp.compare(array[oldBeginIndex], array[endIndex]) <= 0) endIndex--;
            while (beginIndex < endIndex && cmp.compare(array[oldBeginIndex], array[beginIndex]) >= 0) beginIndex++;
            if (beginIndex < endIndex) {
                swap(array, beginIndex, endIndex);
            }
        }
        if (oldBeginIndex != beginIndex) {
            swap(array, oldBeginIndex, beginIndex);
        }
        return beginIndex;
    }

    /**
     * 快速排序
     * 通过递归,将一个数分成两部分,再将两部分的每部分,再分两部分...直到数组有序结束
     * 相当于分治排序
     * @param array 数组
     * @param beginIndex 开始索引
     * @param endIndex 结束索引
     * @param cmp 比较器
     * @param <T>
     */
    public static <T> void quickSort(T[] array, int beginIndex, int endIndex, Comparator<T> cmp) {
        if(beginIndex >= endIndex) return;
        int midIndex = getMidIndex(array, beginIndex, endIndex, cmp);
        quickSort(array, beginIndex, midIndex - 1, cmp);
        quickSort(array, midIndex + 1, endIndex, cmp);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值