开发者

详解Java List中五种常见实现类的使用

目录
  • 一、 List概述
    • 1.1 List 接口的常见实现类
    • 1.2 List接口都定义了那些方法
  • 二、ArrayList
    • 2.1 ArrayList的特点
    • 2.2 ArrayList使用案例
  • 三、LinkedList
    • 3.1 LinkedList的特点
    • 3.2 LinkedList使用案例
  • 四、Vector
    • 4.1 Vector 的特点
    • 4.2 Vector 使用案例
  • 五、Stack
    • 5.1 Stack 的特点
    • 5.2 Stack 使用案例
  • 六、CopyOnWriteArrayList
    • 6.1 CopyOnWriteArrayList 的特点
    • 6.2 CopyOnWriteArrayList 使用案例
  • 七、总结

    一、 List概述

    Java中的List是一个接口,它继承自Collection接口,代表了一个有序的集合,其中的元素可以重复。List提供了一系列方法用于对集合中的元素进行操作,例如添加、删除、获取元素等。Java中常见的List实现类有ArrayListLinkedListVectorStackCopyOnWriteArrayList

    在实际开发中,List接口是一种频繁使用的数据结构,它提供了丰富的方法来操作有序的元素集合。由于其灵活性和常用性,List在许多场景下被广泛应用,是开发人员经常选择的数据结构之一。

    1.1 List 接口的常见实现类

    Java中提供了非常多的使用的List实现类,本文将重点介绍一下这些类以及他们的应用场景。首先罗列一下本文要介绍的实现类都有哪些。

    详解Java List中五种常见实现类的使用

    1.2 List接口都定义了那些方法

    详解Java List中五种常见实现类的使用

    List接口里面定义的方法还是挺多的,大体可以分为六类,下面我将这些方法分类说明一下:

    详解Java List中五种常见实现类的使用

    1.添加元素:

    • boolean add(E element):向列表的末尾添加一个元素。
    • void add(int index, E element):在指定的索引位置添加一个元素。

    2.获取元素:

    • E get(int index):获取指定索引位置的元素。
    • int indexOf(Object obj):返回指定元素在列表中首次出现的索引。
    • int lastIndexOf(Object obj):返回指定元素在列表中最后出现的索引。

    3.删除元素:

    • boolean remove(Object obj):从列表中删除指定元素的第一个匹配项。
    • E remove(int index):删除指定索引位置的元素。

    4.修改元素:

    E set(int index, E element):替换指定索引位置的元素。

    5.列表大小:

    • int size():返回列表中的元素数量。
    • boolean isEmpty():检查列表是否为空。

    6.遍历元素:

    • 使用迭代器(Iterator)遍历列表中的元素。
    • 使用增强的for循环(for-each)遍历列表中的元素。

    二、ArrayList

    详解Java List中五种常见实现类的使用

    ArrayList是一个动态数组实现的类,它是Java集合框架中List接口的一个常用实现类。与传统的数组相比,ArrayList具有更灵活的长度和操作方式。

    通过使用ArrayList,可以方便地管理和操作元素集合,它是Java开发中常用的数据结构之一。

    2.1 ArrayList的特点

    • 动态数组:ArrayList在内部使用数组来存储元素,并且具有动态扩容的能力。当元素数量超过当前数组容量时,ArrayList会自动增加其容量以容纳更多的元素。
    • 有序集合:ArrayList是一个有序集合,可以按照元素的插入顺序迭代访问元素。
    • 允许重复元素:ArrayList允许存储重复的元素,即可以在列表中存储相同的元素多次。
    • 随机访问:由于ArrayList使用基于索引的数组实现,因此可以通过索引进行快速的随机访问和修改元素。可以使用get(index)方法根据索引获取元素,使用set(index, element)方法根据索引修改元素。
    • 动态修改:ArrayList提供了一系列方法来动态修改列表,包括添加元素、删除元素、插入元素等。常用的方法包括add(element)用于在列表末尾添加元素,remove(element)用于删除指定元素,add(index, element)用于在指定位置插入元素等。
    • 支持迭代器:ArrayList实现了Iterable接口,因此可以使用迭代器来遍历列表中的元素。可以通过iterator()方法获取迭代器,并使用hasNext()和next()方法依次访问元素。
    • 非线程安全:ArrayList不是线程安全的,如果在多个线程同时修改ArrayList时,需要进行外部同步或使用线程安全的替代类,如CopyOnWriteArrayList。

    2.2 ArrayList使用案例

    demo:

    import java.util.ArrayList;
    import java.util.List;
    
    public class ArrayListDemo {
    
        public static void main(String[] args) {
            List<String> fruits = new ArrayList<>();
            fruits.add("苹果");
            fruits编程客栈.add("香蕉");
            fruits.add("榴莲");
            fruits.add("菠萝");
    
            // 获取ArrayList的大小
            int size = fruits.size();
            System.out.println("ArrayList的大小:" + size);
    
            // 访问指定位置的元素
            String element = fruits.get(2);
            System.out.println("索引2上的元素:" + element);
    
            // 修改指定位置的元素
            fruits.set(1, "菠萝蜜");
            System.out.println("修改后的ArrayList:" + fruits);
    
            // 删除指定位置的元素
            String removedElement = fruits.remove(3);
            System.out.println("被删除的元素:" + removedElement);
            System.out.println("删除后的Arrawww.devze.comyList:" + fruits);
    
            // 检查ArrayList是否包含某个元素
            boolean contains = fruits.contains(30);
            System.out.println("ArrayList是否包含30:" android+ contains);
    
            // 清空ArrayList
            fruits.clear();
            System.out.println("清空后的ArrayList:" + fruits);
        }
    
    }
    

    输出结果:

    ArrayList的大小:4

    索引2上的元素:榴莲

    修改后的ArrayList:[苹果, 菠萝蜜, 榴莲, 菠萝]

    被删除的元素:菠萝

    删除后的ArrayList:[苹果, 菠萝蜜, 榴莲]

    ArrayList是否包含30:false

    清空后的ArrayList:[]

    三、LinkedList

    详解Java List中五种常见实现类的使用

    LinkedList是Java集合框架中的一个实现类,它实现了List接口和Deque接口,基于双向链表的数据结构。相比于ArrayListLinkedList在某些场景下具有一些特殊的优势和适用性。

    LinkedList适用于需要频繁进行插入和删除操作的场景,特别是在实现队列和栈时。

    3.1 LinkedList的特点

    • 双向链表:LinkedList内部使用双向链表来存储元素。每个节点都包含对前一个节点和后一个节点的引用,因此在插入和删除元素时,LinkedList比ArrayList更高效。由于不需要像ArrayList那样进行数组的扩容和元素的移动,LinkedList对于频繁的插入和删除操作更快。
    • 高效的插入和删除操作:由于LinkedList的双向链表结构,插入和删除元素的平均时间复杂度为O(1),而在ArrayList中,这些操作的时间复杂度为O(n),其中n是元素的数量。因此,在需要频繁进行插入和删除操作的场景下,LinkedList通常比ArrayList更适合。
    • 低效的随机访问:由于LinkedList是基于链表实现的,访问元素需要从头节点或尾节点开始遍历链表,因此随机访问元素的效率较低。在需要频繁进行随机访问的场景下,ArrayList通常更适合。
    • 适合实现队列和栈:LinkedList实现了Queue接口和Deque接口,因此可以用作队列(先进先出)和栈(后进先出)的数据结构。它提供了相关的方法,如add()和remove()用于队列操作,以及push()和pop()用于栈操作。
    • 内存消耗较大:相比于ArrayList,LinkedList在存储相同数量元素时需要更多的内存,因为每个节点都需要额外的引用来指向前一个节点和后一个节点。

    3.2 LinkedList使用案例

    demo:

    import java.util.LinkedList;
    
    public class LinkedListDemo {
    
        public static void main(String[] args) {
            // 创建一个LinkedList,用于存储字符串
            LinkedList<String> names = new LinkedList<>();
    
            // 添加元素到LinkedList
            names.add("张三");
            names.add("李四");
            names.add("王五");
            names.add("赵六");
    
            // 获取LinkedList的大小
            int size = names.size();
            System.ojavascriptut.println("LinkedList的大小:" + size);
    
            // 访问指定位置的元素
            String element = names.get(2);
            System.out.println("索引2上的元素:" + element);
    
            // 修改指定位置的元素
            names.set(1, "林七");
            System.out.println("修改后的LinkedList:" + names);
    
            // 删除指定位置的元素
            String removedElement = names.remove(3);
            System.out.println("被删除的元素:" + removedElement);
            System.out.println("删除后的LinkedList:" + names);
    
            // 在特定位置插入元素
            names.add(0, "马八");
            System.out.println("插入后的LinkedList:" + names);
    
            // 检查LinkedList是否包含某个元素
            boolean contains = names.contains("李四");
            System.out.println("LinkedList是否包含李四:" + contains);
    
            // 清空LinkedList
            names.clear();
            System.out.println("清空后的LinkedList:" + names);
        }
    
    }
    

    输出结果:

    LinkedList的大小:4

    索引2上的元素:王五

    修改后的LinkedList:[张三, 林七, 王五, 赵六]

    被删除的元素:赵六

    删除后的LinkedList:[张三, 林七, 王五]

    插入后的LinkedList:[马八, 张三, 林七, 王五]

    LinkedList是否包含李四:false

    清空后的LinkedList:[]

    四、Vector

    详解Java List中五种常见实现类的使用

    Vector是Java集合框架中的一个类,它实现了List接口,是一个动态数组(类似于ArrayList)的线程安全版本。与ArrayList相比,Vector具有额外的同步机制,可以在多线程环境中安全地使用。

    虽然Vector具有线程安全的特性,但由于同步机制的开销,它在性能上可能不如ArrayList。因此,如果在单线程环境下工作,建议使用ArrayList;仅在多线程环境下需要线程安全操作时,才考虑使用Vector

    需要注意的是,在Java 5及以后的版本中,推荐使用更加高效的并发集合类,如CopyOnWriteArrayListConcurrentLinkedDeque,来替代Vector,因为它们提供更好的性能和扩展性。

    4.1 Vector 的特点

    • 动态数组:Vector内部使用数组来存储元素,并且具有动态扩容的能力。当元素数量超过当前数组容量时,Vector会自动增加其容量以容纳更多的元素。
    • 线程安全:Vector的操作是线程安全的,即多个线程可以同时对Vector进行操作而不会导致数据不一致或其他线程安全问题。Vector通过使用同步机制来实现线程安全,确保在多线程环境中的并发访问操作的正确性。
    • 有序集合:Vector是一个有序集合,可以按照元素的插入顺序迭代访问元素。
    • 允许重复元素:Vector允许存储重复的元素,即可以在列表中存储相同的元素多次。
    • 随机访问:由于Vector使用基于索引的数组实现,因此可以通过索引进行快速的随机访问和修改元素。可以使用get(index)方法根据索引获取元素,使用set(index, element)方法根据索引修改元素。
    • 动态修改:Vector提供了一系列方法来动态修改列表,包括添加元素、删除元素、插入元素等。常用的方法包括add(element)用于在列表末尾添加元素,remove(element)用于删除指定元素,add(index, element)用于在指定位置插入元素等。
    • 迭代器支持:Vector实现了Iterable接口,因此可以使用迭代器来遍历列表中的元素。可以通过iterator()方法获取迭代器,并使用hasNext()和next()方法依次访问元素。

    4.2 Vector 使用案例

    demo:

    import java.util.Vector;
    
    public class VectorExample {
    
        public static void main(String[] args) {
            // 创建一个Vector,用于存储整数
            Vector<Integer> numbers = new Vector<>heqvDVgyo;();
    
            // 添加元素到Vector
            numbers.add(11);
            numbers.add(22);
            numbers.add(33);
            numbers.add(44);
    
            // 获取Vector的大小
            int size = numbers.size();
            System.out.println("Vector的大小:" + size);
    
            // 访问指定位置的元素
            int element = numbers.get(2);
            System.out.println("索引2上的元素:" + element);
    
            // 修改指定位置的元素
            numbers.set(1, 25);
            System.out.println("修改后的Vector:" + numbers);
    
            // 删除指定位置的元素
            int removedElement = numbers.remove(3);
            System.out.println("被删除的元素:" + removedElement);
            System.out.println("删除后的Vector:" + numbers);
    
            // 在特定位置插入元素
            numbers.add(0, 5);
            System.out.println("插入后的Vector:" + numbers);
    
            // 检查Vector是否包含某个元素
            boolean contains = numbers.contains(30);
            System.out.println("Vector是否包含30:" + contains);
    
            // 清空Vector
            numbers.clear();
            System.out.println("清空后的Vector:" + numbers);
        }
    
    }
    

    输出结果:

    Vector的大小:4

    索引2上的元素:33

    修改后的Vector:[11, 25, 33, 44]

    被删除的元素:44

    删除后的Vector:[11, 25, 33]

    插入后的Vector:[5, 11, 25, 33]

    Vector是否包含30:false

    清空后的Vector:[]

    五、Stack

    详解Java List中五种常见实现类的使用

    Stack(栈)是Java集合框架中的一个类,它实现了"后进先出"(Last-In-First-Out,LIFO)的数据结构。Stack继承自Vector类,因此具有Vector的所有特性,同时提供了一些额外的栈操作方法。

    Stack的主要用途是在需要后进先出操作的场景中,例如在逆序输出、括号匹配、深度优先搜索等算法中常用到。需要注意的是,由于Stack继承自Vector,它具有线程安全的特性,但在性能上可能不如其他非同步的栈实现,如ArrayDeque。因此,在不需要线程安全操作的情况下,可以考虑使用ArrayDeque代替Stack

    5.1 Stack 的特点

    • 后进先出(LIFO):Stack中的元素按照后进先出的顺序进行操作。最后添加的元素将首先被访问或删除,而最先添加的元素将最后被访问或删除。
    • 继承自Vector:Stack继承了Vector类的所有功能,包括动态数组实现、随机访问、动态修改等。由于Stack是Vector的子类,因此可以使用Vector的所有方法来操作栈。
    • 压栈和出栈:Stack提供了push(element)方法用于将元素压入栈顶,以及pop()方法用于从栈顶弹出并返回栈顶元素。通过这两个方法,可以实现栈的基本操作。
    • 查看栈顶元素:Stack提供了peek()方法,用于返回但不删除栈顶元素。这个方法可以用于查看栈顶元素而不改变栈的状态。
    • 判空和栈大小:Stack提供了isEmpty()方法来检查栈是否为空,以及size()方法来获取栈中元素的数量。
    • 搜索元素:Stack提供了search(element)方法,用于在栈中搜索指定元素,并返回相对于栈顶的距离(如果元素存在于栈中)。如果元素不存在于栈中,则返回-1。

    5.2 Stack 使用案例

    demo:

    import java.util.Stack;
    
    public class StackDemo {
    
        public static void main(String[] args) {
            // 创建一个Stack,用于存储整数
            Stack<Integer> stack = new Stack<>();
    
            // 压入元素到栈顶
            stack.push(66);
            stack.push(88);
            stack.push(99);
    
            // 查看栈顶元素
            int topElement = stack.peek();
            System.out.println("栈顶元素:" + topElement);
    
            // 弹出栈顶元素
            int poppedElement = stack.pop();
            System.out.println("弹出的元素:" + poppedElement);
    
            // 查看栈的大小
            int size = stack.size();
            System.out.println("栈的大小:" + size);
    
            // 判断栈是否为空
            boolean isEmpty = stack.isEmpty();
            System.out.println("栈是否为空:" + isEmpty);
        }
    
    }
    

    输出结果:

    栈顶元素:99

    弹出的元素:99

    栈的大小:2

    栈是否为空:false

    六、CopyOnWriteArrayList

    详解Java List中五种常见实现类的使用

    CopyOnWriteArrayList是Java并发集合框架中的一种线程安全的列表实现。

    由于CopyOnWriteArrayList的写操作会创建新的副本,因此在多个线程同时进行写操作时,不会发生数据不一致的情况。最终输出的列表中包含了所有写线程添加的元素。

    注意,由于CopyOnWriteArrayList的特性,读取操作不会受到写操作的影响,因此可以安全地在写操作进行时进行读取操作。

    6.1 CopyOnWriteArrayList 的特点

    • 线程安全:CopyOnWriteArrayList通过在修改操作时创建一个新的副本来实现线程安全性。这意味着多个线程可以同时进行读取操作,而不会阻塞彼此,且读取操作不会受到修改操作的影响。
    • 写时复制:在修改操作(如添加、修改、删除元素)时,CopyOnWriteArrayList会创建一个数组的新副本,以保持原有数组的不可变性。这意味着修改操作不会直接修改原始数组,而是在新副本上进行操作,从而保证了读取操作的线程安全性。
    • 高效的读取操作:由于读取操作不需要进行同步或加锁,所以读取操作的性能很高。适用于读多写少的场景。
    • 适用于静态数据集:CopyOnWriteArrayList适用于静态数据集,即在创建后很少有修改操作。如果需要频繁进行修改操作,可能会产生较高的内存开销,因为每次修改都会创建新的副本。

    6.2 CopyOnWriteArrayList 使用案例

    demo:

    import java.util.concurrent.CopyOnWriteArrayList;
    
    public class CopyOnWriteArrayListDemo {
    
        public static void main(String[] args) {
            // 创建一个CopyOnWriteArrayList,用于存储整数
            CopyOnWriteArrayList<Integer> numbers = new CopyOnWriteArrayList<>();
    
            // 创建并启动多个线程进行写操作
            for (int i = 0; i < 5; i++) {
                int finalI = i;
                Thread thread = new Thread(() -> {
                    numbers.add(finalI);
                    System.out.println("线程" + Thread.currentThread().getName() + ":添加元素 " + finalI);
                });
                thread.start();
            }
    
            // 等待所有写线程执行完毕
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            // 输出列表中的元素
            System.out.println("列表中的元素:" + numbers);
        }
    
    }
    

    输出结果:

    线程Thread-0:添加元素 0

    线程Thread-4:添加元素 4

    线程Thread-3:添加元素 3

    线程Thread-1:添加元素 1

    线程Thread-2:添加元素 2

    列表中的元素:[0, 1, 3, 4, 2]

    七、总结

    ArrayList、LinkedList、Vector、Stack和CopyOnWriteArrayList都是Java集合框架中的List的实现类,用于存储有序的元素集合,但它们在底层数据结构、线程安全性以及性能特点上存在一些差异。

    在实际开发中我们要根据业务的需求来合理的选择不同的数据结构。

    以上就是详解Java List中五种常见实现类的使用的详细内容,更多关于Java List的资料请关注编程客栈(www.devze.com)其它相关文章!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜