ArrayList 和 顺序表

ArrayList是Java中的动态数组,提供比静态数组更灵活的增删改操作。它实现了Collection和List接口,方便使用。本文将探讨ArrayList的构造、常用方法、遍历方式(包括for循环、foreach和迭代器)以及其扩容机制。在扩容时,ArrayList会根据需要按1.5倍或用户指定大小进行扩展,并确保扩容操作成功。

在我们之前的学习中,我们已经接触到了数组,在Java里,使用数组解决问题是十分高效的;但是,我们知道,数组一但被初始化时候,那么他的长度就不能再改变了;即数组是静态的。

我们在数据结构这里引进可一种新型的结构——ArrayList。ArrayList就是传说中的动态数组,我们可以把它看作是Array的复杂版本,在我们使用的过程中,他可以为我们带来更好的使用:比如说:

  1. 我们可以动态的增加、减少元素;
  2. 我们可以灵活的设置数组的大小;
  3. 实现了Collection和list接口在使用时更简单。

ArrayList的使用

1. ArrayList的构造

ArrayList()无参构造
ArrayList(Collection<? extends E> c)利用其他 Collection 构建 ArrayList
ArrayList(int initialCapacity)指定顺序表初始容量
    public static void main(String[] args) {
        // 1.无构造参数
        List<Integer> list = new ArrayList<>();

        // 2.构造一个指定顺序表初始容量
        List<Integer> list1 = new ArrayList<>(10);
        list1.add(1);
        list1.add(2);
        list1.add(3);

        // 3.list2,list3构造好后,与list2一致
        ArrayList<Integer> list2 = new ArrayList<>(list1);
        List<Integer> list3 = new ArrayList<>(list1);
        // 4.注意:不要忘记<>里的类型
    }

2. ArrayList常见的方法

方法解释
boolean add(E e)尾插 e
void add(int index, E element)将 e 插入到 index 位置
boolean addAll(Collection<? extends E> c)尾插 c 中的元素
E remove(int index)删除 index 位置元素
boolean remove(Object o)删除遇到的第一个 o
E get(int index)获取下标 index 位置元素
E set(int index, E element)将下标 index 位置元素设置为 element
void clear()清空
boolean contains(Object o)判断 o 是否在线性表中
int indexOf(Object o)返回第一个 o 所在下标
int lastIndexOf(Object o)返回最后一个 o 的下标
List<E> subList(int fromIndex, int toIndex)

截取部分 list

具体的使用过程:------》 

    public static void main(String[] args) {
        // 1.无构造参数
        //List<Integer> list = new ArrayList<>();

        // 2.构造一个指定顺序表初始容量
        List<Integer> list1 = new ArrayList<>(10);
        list1.add(1);
        list1.add(2);
        list1.add(3);
        list1.add(4);
        list1.add(5);
        list1.add(6);
        // 3.list2,list3构造好后,与list2一致
        //ArrayList<Integer> list2 = new ArrayList<>(list1);
        //List<Integer> list3 = new ArrayList<>(list1);
        // 4.注意:不要忘记<>里的类型
        System.out.println("第一次add "+list1);
        System.out.println("size "+list1.size());
        System.out.println("1位置元素 "+list1.get(1));
        list1.add(1,9);
        System.out.println("修改后1位置 "+list1.get(1));
        System.out.println("===========================================");
        list1.remove(1);
        System.out.println(list1);
        System.out.println(list1.contains(3));
        list1.add(1);
        System.out.println(list1.indexOf(1));
        System.out.println(list1.lastIndexOf(1));
        List<Integer> list2 = list1.subList(1,4);
        System.out.println(list2);

    }

 3. ArrayList的遍历

有三种遍历方式:

  1. for循环;
            // 1.遍历
            for (int i = 0; i < list1.size(); i++) {
                System.out.print(list1.get(i) + " ");
            }
            System.out.println();
  2. foreach;
            // 2.foreach
            for (Integer a:list1) {
                System.out.print(a+ " ");
            }
            System.out.println();
  3. 使用迭代器;
            // 3.使用迭代器
            Iterator<Integer> interator = list1.iterator();
            while (interator.hasNext()) {
                System.out.print(interator.next()+" ");
            }
            System.out.println();

4. ArrayList的扩容机制 

我们知道ArrayList是动态数组,那他底层是如何进行扩容的呢?

我们进入他的源码,来探究。

Object[] elementData; // 存放元素的空间
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 默认空间
private static final int DEFAULT_CAPACITY = 10; // 默认容量大小
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
} r
eturn minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// 获取旧空间大小
int oldCapacity = elementData.length;
// 预计按照1.5倍方式扩容
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果用户需要扩容大小 超过 原空间1.5倍,按照用户所需大小扩容
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果需要扩容大小超过MAX_ARRAY_SIZE,重新计算容量大小
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 调用copyOf扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
// 如果minCapacity小于0,抛出OutOfMemoryError异常
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}

总结:

1. 检测是否真正需要扩容,如果是调用grow准备扩容
2. 预估需要库容的大小

  • 初步预估按照1.5倍大小扩容
  • 如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容
  • 真正扩容之前检测是否能扩容成功,防止太大导致扩容失败

3. 使用copyOf进行扩容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值