浅析 ArrayList

by emanjusaka from www.emanjusaka.top/2023/12/jav... 彼岸花开可奈何

本文欢迎分享与聚合,全文转载请留下原文地址。

ArrayList是一个使用List接口实现的Java类。顾名思义,Java ArrayList提供了动态数组的功能,其中数组的大小不是固定的。它实现了所有可选的列表操作,并允许所有元素,包括null。

ArrayList 继承于 AbstractList ,实现了 List, RandomAccess, Cloneable, java.io.Serializable 这些接口。

java 复制代码
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{

  }

ArrayList 中的构造函数

java 复制代码
// 默认初始化容量
private static final int DEFAULT_CAPACITY = 10;
// 用于空实例的共享空数组实例。
private static final Object[] EMPTY_ELEMENTDATA = {};
// 用于默认大小的空实例的共享空数组实例。我们将其与EMPTY_ELEMENTDATA区别开来,以了解添加第一个元素时要膨胀多少。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
  
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {
            if (c.getClass() == ArrayList.class) {
                elementData = a;
            } else {
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }
  • 默认构造函数,使用初始容量10构造一个空列表(无参数构造)
  • 带初始容量参数的构造函数。(用户自己指定容量)
  • 构造包含指定collection元素的列表,这些元素利用该集合的迭代器按顺序返回

自动扩容

java 复制代码
public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;
        // 最小容量大于初始容量
        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            // 扩容
            grow(minCapacity);
    }

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
      private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

当我们在 Java 中创建 ArrayList 时,它的默认容量为 10。如果添加的元素多于初始容量,则 ArrayList 可以自动调整大小。如果确定需要添加到 ArrayList 的最小元素数,则可以使用ensureCapacity()​​方法指定。

  • 初始容量:当创建一个新的 ArrayList 时,它会指定一个初始容量。这个初始容量决定了 ArrayList 可以容纳多少个元素,而不必扩容。

  • 扩容因子:ArrayList 还具有一个扩容因子,它决定了当 ArrayList 需要扩容时,它的容量将增加多少。扩容因子通常是一个大于 1 的数字,例如 1.5 或 2。

  • 扩容条件:当 ArrayList需要添加一个新元素时,它会检查其当前容量是否足够。如果当前容量不够,它将进行扩容。

  • 扩容过程:扩容过程包括以下步骤:

    • 创建一个新的数组,其容量为当前容量乘以扩容因子。
    • 将 ArrayList 中的所有元素复制到新的数组中。
    • 将新的数组设置为 ArrayList 的 backing 数组。
    • 将 ArrayList 的容量更新为新的容量。

ArrayList的重要特性

  • ArrayList继承AbstractList类并实现List接口。
  • ArrayList按大小初始化。但是,如果集合增大,则大小会自动增加;如果从集合中删除对象,则大小会自动减小。
  • ArrayList允许我们随机访问列表。
  • ArrayList 不能用于原始类型,如 int、char 等。我们需要一个包装类来处理这种情况。
  • Java中的ArrayList可以看作C++中的向量。
  • ArrayList 不同步。 Java 中它的等价同步类是 Vector。

ArrayList 中方法

  • add(int index, Object element):该方法用于在列表中的特定位置索引处插入特定元素。
  • add(Object o):此方法用于将特定元素附加到列表末尾。
  • addAll(Collection c):此方法用于将特定集合中的所有元素附加到所提到的列表的末尾,按照指定集合的迭代器返回值的顺序。
  • addAll(int index, Collection c):用于将特定集合中从指定位置开始的所有元素插入到提到的列表中。
  • clear():此方法用于从任何列表中删除所有元素。
  • clone():该方法用于返回 Java 中 ArrayList 的浅表副本。
  • contains(Object o):如果此列表包含指定元素,则返回 true。
  • ensureCapacity(int minCapacity):如有必要,增加此 ArrayList 实例的容量,以确保它至少可以容纳最小容量参数指定的元素数量。
  • forEach(Consumer<? super E> action):对 Iterable 的每个元素执行给定的操作,直到处理完所有元素或该操作引发异常。
  • get(int index):返回此列表中指定位置的元素。
  • indexOf(Object o):返回特定元素第一次出现的索引,如果该元素不在列表中,则返回 -1。
  • isEmpty():如果此列表不包含任何元素,则返回 true。
  • lastIndexOf(Object o):返回特定元素最后一次出现的索引,如果该元素不在列表中,则返回 -1。
  • listIterator():返回此列表中元素的列表迭代器(按正确的顺序)。
  • listIterator(int index):返回列表中元素的列表迭代器(按正确的顺序),从列表中的指定位置开始。
  • remove(int index):删除此列表中指定位置的元素。
  • remove(Object o):从此列表中删除第一次出现的指定元素(如果存在)。
  • removeAll(Collection c):从此列表中删除指定集合中包含的所有元素。
  • removeIf(Predicate filter):删除此集合中满足给定谓词的所有元素。
  • removeRange(int fromIndex, int toIndex):从此列表中删除索引介于 fromIndex(包含)和 toIndex(不包含)之间的所有元素。
  • retainAll(Collection<?> c):仅保留此列表中指定集合中包含的元素。
  • set(int index, E element):将此列表中指定位置的元素替换为指定元素。
  • size():返回此列表中的元素数量。
  • spliterator():在此列表中的元素上创建一个后期绑定和快速失败的 Spliterator。
  • subList(int fromIndex, int toIndex):返回此列表中指定的 fromIndex(包含)和 toIndex(不包含)之间的部分的视图。
  • toArray():此方法用于返回一个数组,其中包含按正确顺序排列的列表中的所有元素。
  • toArray(Object[] o):它还用于返回一个包含此列表中所有元素的数组,其顺序与之前的方法相同。
  • trimToSize():此方法用于将 ArrayList 实例的容量修剪为列表的当前大小。

向 ArrayList 添加元素

可以使用 add() 方法向 ArrayList 添加元素。

java 复制代码
// 这将在列表末尾添加"emanjusaka"
aList.add("emanjusaka");

// 这将在第四个位置添加"emanjusaka"
aList.add(3,"emanjusaka");

更改 ArrayList 中的元素

可以使用 set() 方法更改 ArrayList 中的元素。需要提供索引和新元素,然后此方法用新的给定元素更新给定索引处存在的元素。

java 复制代码
package top.emanjusaka;

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> aList = new ArrayList<>();
        aList.add("emanjusaka");
        aList.add("Tom");
        aList.add("Jack");
        aList.set(1, "Jerry");
        System.out.println(aList);

    }
}

输出结果:

从 ArrayList 中移除元素

可以使用 remove() 方法从 ArrayList 中移除元素。

java 复制代码
package top.emanjusaka;

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> aList = new ArrayList<>();
        aList.add("emanjusaka");
        aList.add("Tom");
        aList.add("Jack");
        System.out.println(aList);
        aList.remove("Tom");
        System.out.println(aList);
        aList.remove(1);
        System.out.println(aList);

    }
}

输出结果:

迭代 ArrayList

java 复制代码
package top.emanjusaka;

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> aList = new ArrayList<>();
        aList.add("emanjusaka");
        aList.add("Tom");
        aList.add("Jack");
        for (String s : aList) {
            System.out.println(s);
        }

    }
}

输出结果:

ArrayList 大小

可以使用ArrayList的size() 方法来查找ArrayList中的元素数量。

java 复制代码
package top.emanjusaka;

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> aList = new ArrayList<>();
        aList.add("emanjusaka");
        aList.add("Tom");
        aList.add("Jack");
        System.out.println("Number of elements in ArrayList: " + aList.size());

    }
}

输出结果:

对 ArrayList 进行排序

可以使用 Collections 实用程序类的 sort() 方法对 ArrayList 进行排序。

java 复制代码
package top.emanjusaka;

import java.util.ArrayList;
import java.util.Collections;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> aList = new ArrayList<>();
        aList.add("emanjusaka");
        aList.add("Tom");
        aList.add("Jack");
        Collections.sort(aList);
        for (String s : aList) {
            System.out.println(s);
        }

    }
}

输出结果:

参考资料

本文原创,才疏学浅,如有纰漏,欢迎指正。如果本文对您有所帮助,欢迎点赞,并期待您的反馈交流,共同成长。

原文地址: www.emanjusaka.top/2023/12/jav...

微信公众号:emanjusaka的编程栈

相关推荐
考虑考虑1 小时前
JDK9中的dropWhile
java·后端·java ee
想躺平的咸鱼干1 小时前
Volatile解决指令重排和单例模式
java·开发语言·单例模式·线程·并发编程
hqxstudying1 小时前
java依赖注入方法
java·spring·log4j·ioc·依赖
·云扬·2 小时前
【Java源码阅读系列37】深度解读Java BufferedReader 源码
java·开发语言
martinzh2 小时前
Spring AI 项目介绍
后端
Bug退退退1233 小时前
RabbitMQ 高级特性之重试机制
java·分布式·spring·rabbitmq
小皮侠3 小时前
nginx的使用
java·运维·服务器·前端·git·nginx·github
前端付豪3 小时前
20、用 Python + API 打造终端天气预报工具(支持城市查询、天气图标、美化输出🧊
后端·python
爱学习的小学渣3 小时前
关系型数据库
后端
武子康3 小时前
大数据-33 HBase 整体架构 HMaster HRegion
大数据·后端·hbase