Java集合之List集合(上)

简介: Java集合之List集合

一、 List概述

1.1概念

List是一种常用的集合类型,它可以存储任意类型的对象,也可以结合泛型来存储具体的类型对象,本质上就是一个容器

1.2体系

List中主要有ArrayList、LinkedList两个实现类

1.3 通用方法

ArrayList和LinkedList通用方法

方法名 说明
public boolean add(要添加的元素) 将指定的元素追加到此集合的末尾
public boolean remove(要删除的元素) 删除指定元素,返回值表示是否删除成功
public E remove(int index) 删除指定索引处的元素,返回被删除的元素
public E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
public E get(int index) 返回指定索引处的元素
public int size() 返回集合中的元素的个数
boolean contains(Object o) 如果此列表包含指定的元素,则返回 true
boolean addAll(int index, Collection<? extends E> c) 将指定集合中的所有元素插入到此列表中,从指定的位置开始
void clear() 列表中删除所有元素

这里以ArrayList举例

代码测试:

public static void main(String[] args) {
    // TODO Auto-generated method stub
    // 创建集合
    List list = new ArrayList<>();
    // 添加元素
    list.add("hello");
    list.add("world");
    list.add("java");
    // public boolean remove(Object o):删除指定的元素,返回删除是否成功
     System.out.println(list.remove("world"));//true
     System.out.println(list.remove("javaee"));//false
    // public E remove(int index):删除指定索引处的元素,返回被删除的元素
     System.out.println(list.remove(1));//world
    // IndexOutOfBoundsException
     System.out.println(list.remove(3));
    // public E set(int index,E element):修改指定索引处的元素,返回被修改的元素
     System.out.println(list.set(1,"javaee"));//world
    // IndexOutOfBoundsException
     System.out.println(list.set(3,"javaee"));
    // public E get(int index):返回指定索引处的元素
     System.out.println(list.get(0));//hello
     System.out.println(list.get(1));//world
     System.out.println(list.get(2));//java
    // IndexOutOfBoundsException
     System.out.println(list.get(3));
    // public int size():返回集合中的元素的个数
     System.out.println(list.size());//3
    // 输出集合
     System.out.println("list:" + list);//list:[hello, world, java]
    // boolean contains(Object o) 如果此列表包含指定的元素,则返回 true
     System.out.println(list.contains("world"));//true
    // boolean addAll(int index, Collection c) 
    //将指定集合中的所有元素插入到此列表中,从指定的位置开始
    List list2 = new ArrayList<>();
    //addall前list2
    System.out.println(list2);// []
    System.out.println(list2.addAll(0, list));// true
    //addall后list2
    System.out.println(list2);// [hello, world, java]
  }

二、List的特点

(1)有序性:List中的元素是按照添加顺序进行存放的。因为有序,所以有下标,下标从0开始

(2)可重复性: List中可以存储重复的元素

三、遍历方式

3.1 foreach

List list = new ArrayList<>();
        //添加元素
        list.add("hello");
        list.add("world");
        list.add("java");
        for (Object object : list) {
      System.out.println(object);
    }

3.2 for循环

根据下标遍历

//创建集合
       List list = new ArrayList<>();
        //添加元素
        list.add("hello");
        list.add("world");
        list.add("java");
       for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
  }

3.3迭代器

//创建集合
       List list = new ArrayList<>();
        //添加元素
        list.add("hello");
        list.add("world");
        list.add("java");
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
          System.out.println(iterator.next());
    }

四、ArrayList

4.1ArrayList概述

4.1.1概念

ArrayList是Java中的一个类,实现了List接口,底层使用数组来存储元素。与数组相比,它具有更灵活的大小和动态的增加和删除元素。

4.1.2数据结构

ArrayList的数据结构本质上就是数组。区别在于,数组是一种静态的数据结构,需要在创建数组时就指定它的长度,并且创建后长度无法改变。而ArrayList是一种动态的数据结构,它可以自动进行扩容。

ArrayList的底层数据结构:

4.2ArrayList的特点

除了具备List有序性、可重复性特点外,ArrayList还具备以下的特点:

4.2.1自动扩容

当向ArrayList中加入的元素超过了其默认的长度时(由于ArrayList是数组的封装类,在创建ArrayList时不用给定长度,其默认长度为10),它会自动扩容以增加存储容量

4.2.2随机访问

随机访问是指可以直接访问元素,而不需要从头部或者尾部遍历整个列表。由于ArrayList底层是用数组实现的,因此可以通过索引来快速访问元素。

4.2.3 慢速插入/删除:

相比于链表(如LinkedList),ArrayList在中间插入或删除元素较慢,因为需要移动元素。

4.2.4高效的遍历

由于ArrayList底层采用了数组来存储元素,所以对于ArrayList的遍历操作比较高效。

4.3常用方法

方法名 说明
trimToSize() 将内部存储的数组大小调整为列表中元素的实际数量。
ensureCapacity(int minCapacity) 设置内部存储的数组大小,以容纳指定数量的元素。
toArray(T[] a) 将列表中的元素转换为指定类型的数组

代码测试:

package com.xqx.list;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class demo4 {
public static void main(String[] args) throws Exception {
  //创建一个容量为100的集合
  ArrayList list = new ArrayList(100);
  //新增数据前容量
  elementDataLength(list); //当前List集合容量为:100
  for (int i = 0; i < 101; i++) {
    list.add(i);//增加101个元素
  }
  //新增数据后容量大小
  elementDataLength(list); //当前List集合容量为:150
  list.trimToSize();
  //调用trimToSize()方法后容量大小,能够避免资源浪费
  elementDataLength(list); //当前List集合容量为:101
  //创建一个容量为4的集合
  ArrayList list2 = new ArrayList(4);
  elementDataLength(list2);//当前List集合容量为:4
  list2.add(1);
  list2.add(2);
  list2.add(3);
  list2.add(4);
  list2.add(5);
  //超过4个元素自动扩容 4*1.5=6
  elementDataLength(list2);//当前List集合容量为:6
  //手动扩容,减少扩容次数,影响性能
  list2.ensureCapacity(100);
  elementDataLength(list2);//当前List集合容量为:100
  Integer[] arr = new Integer[list2.size()];//注意,传入的数组长度应该至少等于ArrayList的元素个数,否则将会抛出空指针异常。
  for (Integer integer : arr) {
    System.out.println(integer);//null null null null null
  }
  list2.toArray(arr);
  for (Integer integer : arr) {
    System.out.println(integer);// 1 2 3 4 5
  }
}
/**
 * 定义一个名为 "elementDataLength" 的方法,该方法用于使用反射获取 ArrayList 中存储元素的底层数组的长度并输出
 * 
 */
public static void elementDataLength(List list) throws Exception {
  // 使用反射获取 ArrayList 对象的成员变量 elementData
  Field ed = list.getClass().getDeclaredField("elementData");
  ed.setAccessible(true); // 设置允许访问私有变量
  Object[] o = (Object[]) ed.get(list); // 获取 ArrayList 中存储元素的底层数组对象的引用
  // 输出 ArrayList 的容量信息,即底层数组的长度
  System.out.println("当前List集合容量为:" + o.length);
}
}

4.4 增长因子论证

我们说ArrayList的底层数据结构是数组,而数组的长度是固定的,但ArrayList长度却是可变的。这里就能产生两个问题:

1、数组和ArrayList的性质都不一样,你怎么能说ArrayList的底层数据结构是数组?

2、即使你已经证明了ArrayList的底层数据结构是数组,那为什么数组的长度是固定的,但ArrayList长度却是可变的?

4.4.1证明ArrayList的底层数据结构是数组

证明第一个问题其实很简单,我们查看源代码即可:

(1):

(2):

(3):

我们一步步往上查看,可以看到有一个名为 elementData 的字段: transient Object[] elementData;

这个字段是用于存储 ArrayList 中所有元素的数组。

通过这些代码实现,我们可以看到 ArrayList 的内部实现确实是基于数组实现的。

4.4.2证明ArrayList的容量可变

证明第二个问题,跟我们ArrayList的一个特点密切相关,没错,聪明的你已经猜出来了,就是自动扩容:

在ArrayList中,每当添加一个元素时,都需要先检查当前数组容量是否足够,如果容量不足,则需要进行扩容操作。而ArrayList的扩容机制是:将原数组的长度乘以一个增长因子,通常是1.5,生成一个新的大数组,然后将原数组中的元素复制到新数组中来,这样就完成了扩容操作。


Java集合之List集合(下)https://developer.aliyun.com/article/1386304

目录
相关文章
|
10天前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。HashSet基于哈希表实现,提供高效的元素操作;TreeSet则通过红黑树实现元素的自然排序,适合需要有序访问的场景。本文通过示例代码详细介绍了两者的特性和应用场景。
30 6
|
10天前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
27 3
|
10天前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
20 2
|
12天前
|
存储 算法 Java
Java Set因其“无重复”特性在集合框架中独树一帜
【10月更文挑战第14天】Java Set因其“无重复”特性在集合框架中独树一帜。本文深入解析Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定的数据结构(哈希表、红黑树)确保元素唯一性,并提供最佳实践建议,包括选择合适的Set实现类和正确实现自定义对象的`hashCode()`与`equals()`方法。
23 3
|
6天前
|
安全 Java 程序员
深入Java集合框架:解密List的Fail-Fast与Fail-Safe机制
本文介绍了 Java 中 List 的遍历和删除操作,重点讨论了快速失败(fail-fast)和安全失败(fail-safe)机制。通过普通 for 循环、迭代器和 foreach 循环的对比,详细解释了各种方法的优缺点及适用场景,特别是在多线程环境下的表现。最后推荐了适合高并发场景的 fail-safe 容器,如 CopyOnWriteArrayList 和 ConcurrentHashMap。
34 5
|
5天前
|
Java 程序员 编译器
Java|如何正确地在遍历 List 时删除元素
从源码分析如何正确地在遍历 List 时删除元素。为什么有的写法会导致异常,而另一些不会。
14 3
|
5天前
|
Java 程序员
Java|List.subList 踩坑小记
不应该仅凭印象和猜测,就开始使用一个方法,至少花一分钟认真读完它的官方注释文档。
9 1
|
8天前
|
安全 Java 程序员
Java集合之战:ArrayList vs LinkedList,谁才是你的最佳选择?
本文介绍了 Java 中常用的两个集合类 ArrayList 和 LinkedList,分析了它们的底层实现、特点及适用场景。ArrayList 基于数组,适合频繁查询;LinkedList 基于链表,适合频繁增删。文章还讨论了如何实现线程安全,推荐使用 CopyOnWriteArrayList 来提升性能。希望帮助读者选择合适的数据结构,写出更高效的代码。
28 3
|
10天前
|
存储 Java 数据处理
Set 是 Java 集合框架中的一个接口,不包含重复元素且不保证元素顺序。
【10月更文挑战第16天】Java Set:无序之美,不重复之魅!Set 是 Java 集合框架中的一个接口,不包含重复元素且不保证元素顺序。通过 hashCode() 和 equals() 方法实现唯一性,适用于需要唯一性约束的数据处理。示例代码展示了如何使用 HashSet 添加和遍历元素,体现了 Set 的高效性和简洁性。
19 4
|
12天前
|
存储 Java 数据处理
Set 是 Java 集合框架中的一个接口,不包含重复元素且不保证元素顺序。
Java Set:无序之美,不重复之魅!Set 是 Java 集合框架中的一个接口,不包含重复元素且不保证元素顺序。它通过 hashCode() 和 equals() 方法确保元素唯一性,适用于需要唯一性约束的数据处理。示例代码展示了如何使用 HashSet 实现这一特性。
16 5