java小白日记38(集合-List)

List接口基本介绍

List接口是collection接口的子接口

(1)List集合类中元素有序 (即添加顺序和取出顺序一致)、且可以重复

(2)List集合中的每个元素都有其对应的顺序索引,即支持索引

(3)List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素

(4)JDK API中List接口的实现类常用的有:ArrayList、LinkedList、Vector

List接口方法使用

java 复制代码
import java.util.ArrayList;
import java.util.List;

public class ListExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        // 添加元素
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");

        // 获取元素
        System.out.println("First element: " + list.get(0));

        // 修改元素
        list.set(1, "Blueberry");

        // 删除元素
        list.remove("Cherry");

        // 遍历列表
        for (String fruit : list) {
            System.out.println(fruit);
        }

        // 检查元素是否存在
        System.out.println("Contains Apple: " + list.contains("Apple"));

        // 列表大小
        System.out.println("List size: " + list.size());
    }
}

ArrayList的注意事项

(1)ArrayList可以加入null

(2)ArrayList是由数组来实现数据存储的

(3)ArrayList基本等同Vector,除了ArrayList是线程不安全的(执行效率高),在多线程情况下,不建议使用ArrayList

ArrayList的底层结构:

(1)ArrayList中维护了一个Object类型的数组elementDate

transient Object[] elementDate;//transient 表示短暂的,表示该属性不会被序列化

(2)当创建ArrayList对象时,如果使用的是无参构造器,则elementDate容量为0,第一次添加,则扩容elementDate为10,如需要再次扩容,则扩容的elementDate为1.5倍

(3)如果使用的是指定大小的构造器,则初始elementDate容量为指定大小,如果需要扩容,则直接扩容elementDate的1.5倍

java 复制代码
import java.util.Arrays;

public class ArrayList<E> {
    // 默认初始容量
    private static final int DEFAULT_CAPACITY = 10;

    // 空数组,用于无参构造器初始化
    private static final Object[] EMPTY_ELEMENTDATA = {};

    // 默认空数组,用于无参构造器初始化(延迟初始化)
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    // 存储元素的数组
    transient Object[] elementData;

    // 当前元素的数量
    private int size;

    // 最大数组容量(Integer.MAX_VALUE - 8)
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    // 无参构造器
    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 boolean add(E e) {
        ensureCapacityInternal(size + 1); // 确保容量足够
        elementData[size++] = e; // 添加元素到数组末尾
        return true;
    }

    // 确保内部容量足够
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            // 如果是无参构造器创建的ArrayList,第一次添加元素时使用默认容量
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }

    // 显式确保容量足够
    private void ensureExplicitCapacity(int minCapacity) {
        if (minCapacity - elementData.length > 0) {
            grow(minCapacity); // 如果当前容量不足,则扩容
        }
    }

    // 扩容方法
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length; // 获取当前容量
        int newCapacity = oldCapacity + (oldCapacity >> 1); // 新容量 = 旧容量 * 1.5
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity; // 如果新容量小于所需容量,则使用所需容量
        }
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            newCapacity = hugeCapacity(minCapacity); // 处理超大容量
        }
        elementData = Arrays.copyOf(elementData, newCapacity); // 创建新数组并复制内容
    }

    // 处理超大容量
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) {
            throw new OutOfMemoryError(); // 如果minCapacity溢出,抛出OutOfMemoryError
        }
        return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
    }

    // 获取当前元素数量
    public int size() {
        return size;
    }

    // 获取当前数组容量(通过反射实现,仅用于测试)
    public int getCapacity() {
        return elementData.length;
    }
}

Vector底层结构:

(1)Vector底层也是一个对象数组,protected Object[] elementDate;

(2)Vector是线程同步的,即线程安全,Vector类的操作方法中带有synchronized

(3)在开发中,需要线程同步安全时,考虑使用Vector

Vector底层结构和ArrayList的比较

LinkedList的底层操作机制:

(1)LinkedList的底层维护了一个双向链表

(2)LinkedList中维护了两个属性first和last

ArrayList和LinkedList的比较

如何选择ArrayList和LinkedList:

(1)如果我们改查多,选择ArrayList

(2)如果增删多,选择LinkedList

(3)一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList

(4)在一个项目中,根据业务灵活选择,也可能这样,一个模块使用ArrayList,另一个模块使用LinkedList

相关推荐
麦兜*34 分钟前
Spring Boot 集成Reactive Web 性能优化全栈技术方案,包含底层原理、压测方法论、参数调优
java·前端·spring boot·spring·spring cloud·性能优化·maven
天上掉下来个程小白37 分钟前
MybatisPlus-06.核心功能-自定义SQL
java·spring boot·后端·sql·微服务·mybatisplus
知了一笑44 分钟前
独立开发第二周:构建、执行、规划
java·前端·后端
今天背单词了吗9801 小时前
算法学习笔记:17.蒙特卡洛算法 ——从原理到实战,涵盖 LeetCode 与考研 408 例题
java·笔记·考研·算法·蒙特卡洛算法
Dcs1 小时前
从 C 到 Rust:一位开发者的 `tmux` 全面移植之旅
java
Maybyy2 小时前
力扣242.有效的字母异位词
java·javascript·leetcode
小小寂寞的城3 小时前
JAVA观察者模式demo【设计模式系列】
java·观察者模式·设计模式
探索java3 小时前
Java并发编程中的StampedLock详解:原理、实践与性能优化
java·stampedlock
界面开发小八哥3 小时前
「Java EE开发指南」如何用MyEclipse将Java项目转换为Web项目?
java·ide·java-ee·eclipse·开发工具·myeclipse
pobu1684 小时前
aksk前端签名实现
java·前端·javascript