• java基础 集合(1)集合概念、 Collection接口 、 List


    目录

     一、集合的概念

    1、集合的框架体系

     二、Collection接口

    1.Collection接口和常用方法

    1.1 常用方法

    2、Collection接口遍历方式

    2.1 使用Iterator(迭代器)

    2.2 foreach (增强for循环)

     三、List接口

    1、List接口的常用方法

    常用方法

    2、ArrayList实现类

    2.1、ArrayList的底层结构和源码分析

    3、Vector 实现类

    4、LinkedList类

    4.1 LinkedList的底层结构

    4.2 源码分析

    List的选择的原则:


     一、集合的概念

    • 数组

      • 长度开始的时候长度必须指定,而且一旦指定,不能更改

      • 保存的必须是同一类型的元素

      • 使用数组增加和删除元素比较麻烦

    • 集合

      • 可以动态保存任意多个对象,使用比较方便

      • 提供一系列方便操作对象的方法 : add remove 等

      • 使用集合添加删除新元素 简洁了

    1、集合的框架体系

    1. 集合主要是两组 (单列集合、双列集合)

    2. Collection 接口有两个很重要的子接口 List 和 Set ,他们的实现子类都是单列集合

    3. Map接口的实现自了一 是双列集合 存放的键值对

     

     

     二、Collection接口

    1.Collection接口和常用方法

    public interface Collection extends Iterable 
    1. Collection实现子类可以存放多个元素,每个元素都可以是Object

    2. 有些Collection的实现类,可以存放重复的元素,有些不可以

    3. 有些Collection的实现类,是有序的,有些不是有序的

    4. Collection接口没有直接的实现子类,是通过它的子接口List和Set来实现的

    1.1 常用方法

    通过 ArrayList来演示Collection的常用方法

    1. add 添加单个元素

    2. remove 删除指定元素

    3. contains 查找元素是否存在

    4. size 获取元素个数

    5. isEmpty 判断是否为空

    6. clear 清空

    7. addAll 添加多个元素

    8. containsAll 查找多个元素是否都存在

    9. removeAll 删除多个元素

      
    1.  public static void main(String[] args) {
    2.        Collection list = new ArrayList();
    3. //       1. add 添加单个元素
    4.        list.add("jack");
    5.        list.add(0);
    6.        list.add(true);
    7.        System.out.println("list:" + list); //list:[jack, 0, true]
    8. //   2. remove 删除指定元素 可以删除 指定元素    
    9.        // list.remove(true); //删除指定元素
    10.        // System.out.println("list:" + list);
    11. //   3. contains 查找元素是否存在   返回结果boolean
    12.           System.out.println(list.contains("jack")); //true
    13. //   4. size 获取元素个数
    14.            System.out.println(list.size()); //3
    15. //   5. isEmpty 判断是否为空
    16.        System.out.println(list.isEmpty()); //false
    17. //   6. clear 清空
    18.        list.clear();
    19.        System.out.println("清空集合后:"+list);  //清空集合后:[]
    20. //   7. addAll 添加多个元素
    21.        List list1 = new ArrayList();
    22.        list1.add("洪龙梅");
    23.        list1.add("李科技");
    24.        list.addAll(list1);
    25.        System.out.println(list); //[洪龙梅, 李科技]
    26. //   8. containsAll 查找多个元素是否都存在
    27.        System.out.println(list.containsAll(list1)); //true
    28. //   9. removeAll 删除多个元素
    29.        list.add("雾都");
    30.        System.out.println(list.removeAll(list1)); //true
    31.        System.out.println(list); //[雾都]
    32.   }
    33. }

    2、Collection接口遍历方式

    2.1 使用Iterator(迭代器)

    1. Iterator称为迭代器,主要用于遍历Collection集合中的元素

    2. 所有实现了Collection接口的集合类都有一个iterator()方法,用于获取实现Iterator接口的对象,即可以返回一个迭代器

    3. Iterator 结构

     

     4.Iterator 仅用于遍历集合,Iterator不存放元素

    注意: 在调用iterator.next() 方法之前,一定要先调用iterator.hasNext()进行检测。

    如果不调用,且下一条记录无效,直接调用iterator.next()方法 会抛出 NoSuchElementException异常

    1. package com.sofwin.controller;
    2. import java.util.ArrayList;
    3. import java.util.Collection;
    4. import java.util.Iterator;
    5. /**
    6. * @packageName: com.sofwin.controller
    7. * @author: wentao
    8. * @date: 2022/10/29 20:02
    9. * @version: 1.0
    10. * @email 1660420659@qq.com
    11. * @description: 迭代器
    12. */
    13. public class CollectionIterator {
    14.    public static void main(String[]args){
    15.        Collection col =new ArrayList();
    16.        col.add(new Book("三国演义","罗贯中",12.3));
    17.        col.add(new Book("文字","罗贯中",144.3));
    18.        col.add(new Book("红龙","柠檬",122.3));
    19.        System.out.println("Collection:"+col);
    20.        //先得到集合对应的迭代器
    21.        Iterator iterator = col.iterator();
    22.        //使用while循环遍历
    23.        while (iterator.hasNext()) {
    24.            System.out.println("树:"+iterator.next());
    25.       }
    26.        //当退出while循环后 这是 Iterator的迭代器,指向了最后的元素
    27.        //会抛出异常 Exception in thread "main" java.util.NoSuchElementException
    28.        //如果不想报错 需要我们重置 迭代器  
    29.        //iterator = col.iterator();
    30.        iterator.next();
    31.   }
    32. }
    33. class  Book {
    34.    private String name;
    35.    private  String author;
    36.    private  double price;
    37.    public Book(String name, String author, double price) {
    38.        this.name = name;
    39.        this.author = author;
    40.        this.price = price;
    41.   }
    42.    public String getName() {
    43.        return name;
    44.   }
    45.    public void setName(String name) {
    46.        this.name = name;
    47.   }
    48.    public String getAuthor() {
    49.        return author;
    50.   }
    51.    public void setAuthor(String author) {
    52.        this.author = author;
    53.   }
    54.    public double getPrice() {
    55.        return price;
    56.   }
    57.    public void setPrice(double price) {
    58.        this.price = price;
    59.   }
    60.    @Override
    61.    public String toString() {
    62.        return "Book{" +
    63.                "name='" + name + '\'' +
    64.                ", author='" + author + '\'' +
    65.                ", price=" + price +
    66.                '}';
    67.   }
    68. }

    2.2 foreach (增强for循环)

    • 增强for循环 不仅可以使用在集合中,也可以运用在数组上

    • 底层仍然是迭代器 (可以认为是简化版的迭代器)

     

    1. public class CollectionFor {
    2. public static void main(String[]args){
    3. Collection col =new ArrayList();
    4. col.add(new Book("三国演义","罗贯中",12.3));
    5. col.add(new Book("文字","罗贯中",144.3));
    6. col.add(new Book("红龙","柠檬",122.3));
    7. for (Object o : col) {
    8. System.out.println(o);
    9. }
    10. }
    11. }

     三、List接口

    1、List接口的常用方法

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

      1. public static void main(String[]args){
      2.        List  list = new ArrayList();
      3.        list.add("jack");
      4.        list.add("tom");
      5.        list.add("mary");
      6.        list.add("jack");
      7.        System.out.println(list);  //[jack, tom, mary, jack] 有序可重复
      8.   }

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

      1. public static void main(String[]args){
      2.        List  list = new ArrayList();
      3.        list.add("jack");
      4.        list.add("tom");
      5.        list.add("mary");
      6.        list.add("jack");
      7.        //索引是从0开始的
      8.        System.out.println(list.get(3));  //jack
      9.   }

    常用方法

    1. add 在索引位置插入元素

    2. addAll 从索引位置开始将元素加入进去

    3. get 通过索引获取值

    4. indexOf 返回首次元素出现的位置

    5. lastIndexOf 返回元素最后一次出现的位置

    6. set 指定索引位置 进行替换

    7. subList 返回starat 到 end索引位置的子集合

    1. public static void main(String[]args){
    2.        List  list = new ArrayList();
    3.        list.add("张三丰");
    4.        list.add("刘备");
    5. //       1. add 在索引位置插入元素
    6.        //在索引1的位置插入一个字符串 如果不加默认是加入尾部的
    7.        list.add(1,"吕布");
    8.        System.out.println(list); //[张三丰, 吕布, 刘备]
    9. //       2. addAll   从索引位置开始将元素加入进去
    10.        List list1 = new ArrayList();
    11.        list1.add("jkac");
    12.        list1.add("tom");
    13.        //在张三丰的后加入这个两个元素
    14.        list.addAll(1,list1);
    15.        System.out.println(list); //[张三丰, jkac, tom, 吕布, 刘备]
    16. //       3. get 通过索引获取值
    17.        //获取第一个元素
    18.        Object o = list.get(0);
    19.        System.out.println(o); //张三丰
    20. //       4. indexOf 返回首次元素出现的位置
    21.        int i = list.indexOf("吕布");
    22.        System.out.println("吕布对应集合中第一次出现的索引:"+i); //3
    23. //       5. lastIndexOf 返回元素最后一次出现的位置
    24.        list.add("吕布");
    25.        int j = list.lastIndexOf("吕布");
    26.        System.out.println("吕布对应集合中最后一次出现的索引:"+j); //5
    27. //       6. set 指定索引位置   进行替换
    28.        list.set(0,"张三丰二");
    29.        System.out.println(list);  //[张三丰二, jkac, tom, 吕布, 刘备, 吕布]
    30. //       7. subList 返回starat 到 end索引位置的子集合 [start,end) 左闭右开
    31.        List list2 = list.subList(0, 3);
    32.        System.out.println(list2); //[张三丰二, jkac, tom]
    33.   }
    34. 注意:这里面的索引都要合法才行,否则会出现报错

    2、ArrayList实现类

    1. ArrayList可以加入多个null。

    2. ArrayList是底层是由数组实现存储数据的

    3. ArrayList基本等同于Vector,除了ArrayList是线程不安全的,在多线程的情况下不推荐使用ArrayList

    2.1、ArrayList的底层结构和源码分析

    先说结论,在看源码

    1. public class ArrayListSource {
    2.    public static void main(String[]args){
    3.        //使用无参构造器创建ArrayList对象
    4. //       ArrayList list = new ArrayList();
    5.        ArrayList list = new ArrayList(8);
    6.        //使用for循环给List集合加载1到10   10个数据
    7.        for (int i = 1; i <= 10; i++) {
    8.            list.add(i);
    9.       }
    10.        //又加到15个数据
    11.        for(int i = 11; i <= 15; i++) {
    12.            list.add(i);
    13.       }
    14.        list.add(100);
    15.        list.add(200);
    16.        list.add(null);
    17.   }
    18. }

    1、ArrayList中维护了一个Object类型的数组elementData

    transient Object[] elementData
    // transient 表示瞬间、短暂的、表示该属性不会被序列化

    2、当创建ArrayList对象时,如果使用的无参构造器,则初始elementData容量为0.第一次添加的时候,则扩容为10,如果需要再次扩容,则扩容elementData的1.5倍

    • 代表使用无参构造器,会初始elementData容量为0

     

    • 执行list.add

      • 先确定是否要扩容

     

     

    • calculateCapacity 该方法确定第一次扩容为10

     

    • modCount++ 记录集合被修改的次数(防止多线程 --出现抛出异常)

    • if (minCapacity - elementData.length > 0)
          grow(minCapacity);
       如果elementData的长度不够了,就调用grow去扩容 

     

    • grow

      • 真的扩容

      • 第一次newCapacity = 10

      • 第二次及以后就是按照1.5倍扩容

      • 扩容使用的是 Arrays.copyOf() --->会保留原先的数据

     

    • 将传入值放入数组中

     


    当容量不够的情况

    • 添加第11个元素的时候

     

    • 扩容1.5倍 将之前的10个元素加入到新扩容为15的数组中,然后赋值给elementData

     

     

     debug显示更加全面的话(出现上面那个样子  可以这样设置)

     

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


    3、Vector 实现类

    1. Vector底层也是一个对象数组

      protected Object[] elementData;
    2. Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized

      public synchronized boolean add(E e) {
              modCount++;
              ensureCapacityHelper(elementCount + 1);
              elementData[elementCount++] = e;
              return true;
          }
    3. 在开发中,需要线程安全时,考虑使用Vector

    4. 如果无参 默认是10 每次扩容2倍

     

    •     每次扩容2倍  

    5.如果是有参 按照指定大小 每次扩容2倍  


    4、LinkedList类

    1. LinkedList底层实现了双向链表和双端队列的特点

    2. 可以添加任意元素(元素可以重复),包括null

    3. 线程不安全,没有实现同步

    4.1 LinkedList的底层结构

    1. LinkedList底层维护了一个双向链表

    2. LinkedList中维护了两个属性first和last 分别指向首节点和尾节点

    3. 每个节点(Node对象 ),里面又维护了prev、next、item三个属性,其中prev指向前一个节点,next指向后一个节点。最终实现双向链表

    4. 所以LinkedList的元素 添加和删除,不是通过数组完成的,相对来说效率比较高

    4.2 源码分析

    1. package com.sofwin.controller;
    2. import java.util.LinkedList;
    3. /**
    4. * @packageName: com.sofwin.controller
    5. * @author: wentao
    6. * @date: 2022/10/31 16:18
    7. * @version: 1.0
    8. * @description: LinkedList的源码
    9. */
    10. @SuppressWarnings("all")
    11. public class LinkedListSource {
    12.    public static void main(String[]args){
    13.        /**
    14.         * 源码解读
    15.         * 1、LinkedList linkedList = new LinkedList();
    16.         *   public LinkedList() {
    17.         *     }
    18.         * 这是普通的类的初始化工作
    19.         * 2、这时 linkedList的属性 frist = null last = null size = 0
    20.         *
    21.         * 3.add方法
    22.         * public boolean add(E e) {
    23.         *         linkLast(e);
    24.         *         return true;
    25.         *     }
    26.         * 4. 将新的结点加入到双向链表的最后(尾插法)
    27.         * private void linkFirst(E e) {
    28.         *         final Node f = first;
    29.         *         final Node newNode = new Node<>(null, e, f);
    30.         *         first = newNode;
    31.         *         if (f == null)
    32.         *             last = newNode;
    33.         *         else
    34.         *             f.prev = newNode;
    35.         *         size++;
    36.         *         modCount++;
    37.         *     }
    38.         *
    39.         */
    40.       LinkedList  linkedList = new LinkedList();
    41.       for (int i = 1; i<=2; i++) {
    42.           linkedList.add(i);
    43.       }
    44.        /**
    45.         * 1、删除 第一个元素
    46.         * public E remove() {
    47.         *         return removeFirst();
    48.         *     }
    49.         * 2、 关键代码是 unlinkFirst(f);
    50.         *   public E removeFirst() {
    51.         *         final Node f = first;
    52.         *         if (f == null)
    53.         *             throw new NoSuchElementException();
    54.         *         return unlinkFirst(f);
    55.         *     }
    56.         * 3、删除第一个元素 然后返回删除元素的item值
    57.         *
    58.         *   private E unlinkFirst(Node f) {
    59.         *         // assert f == first && f != null;
    60.         *         final E element = f.item;
    61.         *         final Node next = f.next;
    62.         *         f.item = null;
    63.         *         f.next = null; // help GC
    64.         *         first = next;
    65.         *         if (next == null)
    66.         *             last = null;
    67.         *         else
    68.         *             next.prev = null;
    69.         *         size--;
    70.         *         modCount++;
    71.         *         return element;
    72.         *     }
    73.         */
    74.       linkedList.remove();
    75.   }
    76. }
    • 无参构造方法 LinkedList linkedList = new LinkedList();

      实际就是初始化工作

    • add 方法

    第一次添加的first last 都指向这个新结点

     

     

    第二次添加的时候 first指向第一个结点 last就指向最后一个结点了

     

     

    • 删除 remove()  

     

    这里只分析remove()其他都大体相同

    显示删除的第一个

    返回删除的元素  

     

    List的选择的原则:

    1. 如果改查的操作多,选择ArrayList

    2. 如果增删的操作多,选择LinkedList

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

    4. 在一个项目中,要根据业务灵活选择。

     

  • 相关阅读:
    红帽权限设置及提权知识点结合
    安全与加密常识(5)自签名证书
    初探微前端
    Lambda 表达式练习
    将光耦合进入单模光纤的最佳工作距离
    双十二选什么牌子的led台灯质量好?2022最新几款真的能护眼的台灯推荐
    DSPE-PEG-FITC,Fluorescein-PEG-DSPE,磷脂-聚乙二醇-荧光素修饰脂质体表面
    易周金融分析 | 银行理财市场渐趋理性;“睡眠信用卡”持续清退
    包分配并不是个好制度
    YOLOv8-Seg改进:Backbone改进 |Next-ViT堆栈NCB和NTB 构建先进的CNN-Transformer混合架构
  • 原文地址:https://blog.csdn.net/weixin_52574640/article/details/127651719