浅析Java-ArrayList,源代码分析

ArrayList

这里写图片描述ArrayList是Java集合框架中的一个重要的类,也是大家经常用到的类。她是如何实现的了?
根据上图我们来分析下.

  • 她继承AbstractList类
  • 实现List<E>接口:说明她是一个可变长度的集合
  • 实现RandomAccess接口:说明她支持快速访问
  • 实现Cloneable接口:说明她可被复制
  • 实现Serializable接口:说明她可被序列化
  • 提供了增、删、改、查等相应功能
源代码分析:
transient Object[] elementData; 

通过上面的代码我们可以看出ArrayList的存储方式其实是按照数组方式存储、为类内部访问权限且是Object类型,表明我们常用的数据类型基本都可存储于ArrayList中。

private static final int DEFAULT_CAPACITY = 10;

ArrayList集合默认长度为10。

    private static final Object[] EMPTY_ELEMENTDATA = {};

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

ArrayList初始化数组定义,为应对不用的构造函数(如下) ArrayList提供了3种构造函数

  • public ArrayList(int initialCapacity):根据参数(长度)初始化指定长度的Object数组
    • 当长度大于0则创建指定长度Object数组
    • 长度为0则创建一个不设置长度的Object对象EMPTY_ELEMENTDATA
    • 如果长度小于0则抛出参数不合法异常IllegalArgumentException
  • public ArrayList():构建一个不设置长度(长度根据集合大小变化)Object数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA
  • public ArrayList(Collection<? extends E> c):根据一个集合创建Object数组
    • 将集合c转为数组
    • 将ArrayList的长度修改为集合长度
      • 如果数组类型不是Object[].class则将数组类型转换为Object[].class类型
    • ArrayList长度修改失败则初始化一个可变长度的空集合EMPTY_ELEMENTDATA
  • public void trimToSize():重新根据集合长度构造/复制数组使集合长度与数组长度一致。
    • modCount是父类AbstractList继承过来用于记录集合修改次数。
    • 重置集合长度,当集合的长度size小于存储数组(elementData)的长度(length)则重新根据集合长度构造/复制数组使集合长度与数组长度一致。
    • 博主看到这个方案还是纠结了比较久。什么时候会用到该方法?当使用该方法的时候是否意味着我们的集合将面临丢失数据的情况(答案在下方)。
  • public void ensureCapacity(int minCapacity):该方法为集合/数组扩容,数组对象不是DEFAULTCAPACITY_EMPTY_ELEMENTDATA则原有长度为0否则为默认值10,如果当前数组长度小于准备扩容的长度则调用ensureExplicitCapacity实现扩容。
  • private void ensureCapacityInternal(int minCapacity):如果当前数组对象为DEFAULTCAPACITY_EMPTY_ELEMENTDATA则比较准备修改的长度是否小于默认值大小,调用ensureExplicitCapacity执行修改
  • private void ensureExplicitCapacity(int minCapacity):集合修改次数自增一次,调用grow实现扩容
  • private void grow(int minCapacity):扩容操作实际实现。先将数组长度修改为原长度的1.5倍(oldCapacity >> 1 将oldCapacity2进制移动1位相当于除以2)如果还是不够则修改为为参数指定长度,如果参数指定长度大于默认最大值MAX_ARRAY_SIZE,小于则使用Arrays.copyOf复制,不足的参数使用null不足,反之则调用hugeCapacity检查长度是否溢出。
  • private static int hugeCapacity(int minCapacity):检查重置长度是否合规,小于0抛出异常,移除则取默认最大值。
  • public int size():获取集合长度
  • public boolean isEmpty():验证集合是否为空
  • public boolean contains(Object o):集合是否包含指定的元素
  • public int indexOf(Object o):对象在集合中第一次出现的索引,不存在返回-1
  • public int lastIndexOf(Object o):对象在集合中最后一次出现的索引,不存在返回-1
  • public Object clone():复制一个具有相同属性的集合对象,注:返回值为全新对象,新旧对象的任何操作互不影响,复制出的对象的操作次数设置为0
  • public Object[] toArray:集合转为数组Object[]
  • public <T> T[] toArray(T[] a) 返回指定类型的数组T[]
  • E elementData(int index):返回指定位置的元素(私有)
  • public E get(int index):返回指定索引位置的元素(公有)
  • public E set(int index, E element) :重新赋值指定位置元素
  • public boolean add(E e) :添加元素到集合结尾
  • public void add(int index, E element) :向指定索引位置添加元素,后续元素索引+1
  • public E remove(int index):移除指定索引位置的元素,后续元素索引-1
  • public boolean remove(Object o):移除元素对象。注:如存在重复元素则只会移除第一个
  • private void fastRemove(int index):移除集合指定索引位置的元素(私有)
  • public void clear():将集合中所有索引的对象设置为null并把size设置为0。题外话:调用这个方法后在释放集合对象之前,集合都将占用内存空间,所以使用后最好跟着调用trimToSize()方法将集合多余内存释放(个人意见,大家有什么好的看法,请纠正)
  • public boolean addAll(Collection<? extends E> c):在集合后面追加集合
  • public boolean addAll(int index, Collection<? extends E> c):向指定索引位置添加集合列表
  • protected void removeRange(int fromIndex, int toIndex):移除指定索引范围内的所有元素
  • private void rangeCheck(int index) :验证指定位置元素是否存在,不存在则抛出异常(注:如果索引<0不会抛出异常)
  • private void rangeCheckForAdd(int index):验证指定位置元素是否存在,不存在则抛出异常(包括<0,别被名字误导,不光是验证是否可插入)
  • private String outOfBoundsMsg(int index) :拼接消息字符串
  • public boolean removeAll(Collection<?> c):根据集合移除集合中存在的所有元素
  • public boolean retainAll(Collection<?> c):根据集合移除集合中不存在的所有元素(removeAll反义)
  • private boolean batchRemove(Collection<?> c, boolean complement):根据参数执行移除
  • private void writeObject(java.io.ObjectOutputStream s):将集合写入ObjectOutputStream流中
  • private void readObject(java.io.ObjectInputStream s):将流中的对象读取出来(跟writeObject对应)这两个方法似乎有些鸡肋,均为私有方法外部无法访问且内部并未调用。
  • public ListIterator<E> listIterator(int index):返回指定索引位置开始的迭代器
  • public ListIterator<E> listIterator();返回集合所有元素的迭代器
  • public Iterator<E> iterator():使用内部类Itr返回迭代器
  • public List<E> subList(int fromIndex, int toIndex):返回fromIndex到toIndex子集合
  • static void subListRangeCheck(int fromIndex, int toIndex, int size):验证获取子集合的索引起止位置是否存在,不存在抛出异常
  • public void forEach(Consumer<? super E> action):定义Lambda表达式遍历方法forEach(Java8新特性)ArrayList间接实现了Iterable接口,该方法是Iterable的 forEach实现/重写。Iterable的forEach代码如下
    /**
     * 对每个{@code Iterable}元素执行特定的操作直到所有的元素被处理或者抛出一个异常。
     * 除非实现类另有定义,否则操作将被按照顺序迭代器的顺序执行(如果迭代器被指定)。
     * 操作抛出的异常将传递给其调用者。
     *
     * @implSpec
     * <p>默认实现类似下边这样::
     * <pre>{@code
     *     for (T t : this)
     *         action.accept(t);
     * }</pre>
     *
     * @param action 每个元素将要被执行的操作
     * @throws NullPointerException 如果指定的操作action是空的
     * @since 1.8
     */
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
// 使用匿名内部类实现
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
list.replaceAll(new UnaryOperator<String>(){
    @Override
    public String apply(String str){
        if(str.length()>3)
            return str.toUpperCase();
        return str;
    }
});
  • public void sort(Comparator<? super E> c):集合排序,使用了Comparator比较器来比较,实现里面的compare方法,compareTo比较之后,返回的参数是int类型,0则表示相等,1表示大于,-1负数则表示小于。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值