• day15_集合_ArrayList


    今日内容

    零、 复习昨日
    一、集合框架体系
    二、Collection
    三、泛型
    四、迭代
    五、List(ArrayList、LinkedList)

    零、 复习昨日

    日期解析的方法签名(字符串–>日期)

    • Date parse(String s)

    日期格式化的方法签名(日期–>字符串)

    • String format(Date date)

    运行时异常有哪些,什么特点

    • RuntimeException及其子类,编码时不用强制处理

    编译期异常有哪些,什么特点

    • 除了以上的都是,编码时必须强制处理

    异常的处理方式哪些,什么区别

    • 抛出,抛出后代码不再执行
    • 捕获,捕获后还可以执行

    finally干什么的

    • 释放资源

    throw和throws什么区别

    • 位置?throw在方法内,throws在方法参数列表()后
    • 后面写?throw后跟1个异常对象,throws后面跟多个异常类名
    • 作用?throw是抛出异常对象的,throws只是声明可能要抛出异常类型

    一、集合框架体系

    数组: 存储多个数据的容器

    • 数组长度固定
    • 数组只能存储同一种类型
    • 数组用法单一,只能通过下标取值赋值
    • 数组内元素可以重复
    • 数组内元素有顺序(存值时顺序)

    集合(Collection): 存储多个数据的容器

    • 集合长度不固定
    • 集合可以存储不同类型
    • 集合是一些列的类,可以创建对象,有丰富的方法可以操作数据
    • 有些集合可以重复(List),有些集合不允许重复(Set);有些集合有序的(List),有些集合是无序的(HashSet),而且有些集合还会排序(TreeSet)

    image-20240308095727002

    • Collection是集合层次的父接口,定义了所有集合共性操作

    • Collection有两个常用子接口:List,Set

    • List接口集合,主要特征是有序,允许重复元素的集合

    • Set接口集合,主要特征是元素去重

    • List接口有两个常用实现类

      • ArrayList,底层是数组,也是允许元素重复,数据有序
      • LinkedList,底层是链表,也是允许元素重复,数据有序
    • Set接口有两个常用实现类

      • HashSet,底层是hash表,存储的元素无序且去重
      • TreeSet,底层是二叉树,存储的元素是排序且去重

    二、Collection、List介绍

    • Collection父接口

      • 定义了一部分集合的共性操作,并不全
    • List是Collection的子接口,有序允许重复的集合

      • 定义了一些方法,可以对位置进行精准控制
      • 即可以按照下标插入,删除,查询,修改集合元素
    • List是接口,不能只能直接用,常用使其子实现类,ArrayList和LinkedList

    三、ArrayList[重点]

    • 是List接口的实现类,允许重复,有序
    • 底层是数组,大小"可变"
    • 是不同步,即不保证线程安全

    3.1 方法演示1

    先演示了部分方法,主要对集合元素 增 删 改 查

       public static void main(String[] args) {
            // 创建空集合
            ArrayList list = new ArrayList( );
            System.out.println("初始值: " + list);
    
            // 向末尾添加元素
            // 有序(插入顺序),允许重复,允许存储不同类型
            list.add(4);
            list.add(2);
            list.add(2);
            list.add(5);
            list.add("六");
            System.out.println("添加值:" + list);
    
            // 向指定下标插入数据
            list.add(2, 1);
            System.out.println("中间插入:" + list);
    
            // 获得指定下标的元素
            Object o = list.get(2);
            System.out.println(o);
    
            // 按照下标修改元素
            list.set(2, 100);
            System.out.println("修改后:" + list);
    
            // 按下下标删除元素
            Object old = list.remove(0);
            System.out.println("被删除掉的元素:" + old );
            System.out.println("删除后的集合:"+list );
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    3.2 泛型

     private static void show2() {
            /**
             * 集合确实可以允许存储不同类型数据
             * 但是大部分情况下,集合只会存储同一类型
             * -----------
             * 目前这种情况,设计时存储的是Object
             * 取出数据也是Object,需要使用对应数据类型时需要强转
             * 但是强制转换有风险
             * ---------------------
             * 所以,在JDK1.5时引入泛型 ,通过泛型就可以解决这个问题
             */
            ArrayList list = new ArrayList(  );
            list.add(1);
            list.add(2.0);
            list.add("3");
            list.add(new Date(  ));
    
            double o = (double) list.get(0);
            System.out.println(o );
            System.out.println("-------------------------" );
    
            /**
             * 下面使用泛型来定义集合
             * 通过在类名后,指定泛型类型,从而确定该集合只能存储指定类型
             * -------------
             * 泛型好处: 减少类型转换(强转)
             */
            ArrayList<Integer> list2 = new ArrayList<>( );
            list2.add(1);// 有了泛型约束,存储时只能是Integer
            list2.add(2);
            list2.add(3);
    
            Integer i = list2.get(2);// 有了泛型约束,取出就是Integer,无需强转
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    以后,凡是用集合操作,必用泛型!!

    3.3 方法演示2

    /**
         * 演示ArrayList其他方法
         */
        private static void show3() {
            ArrayList<Integer> l1 = new ArrayList<>( );
            l1.add(11);
            l1.add(22);
            l1.add(33);
            System.out.println("原始l1:" + l1 );
    
            ArrayList<Integer> l2 = new ArrayList<>( );
            l2.add(10);
            l2.add(20);
            l2.add(30);
    
            // 将另外一个集合中的全部元素加入当前集合
            l1.addAll(l2);
            System.out.println("addAll后: " + l1);
    
            // 移除当前集合中,存在于参数集合相同的元素
            l1.removeAll(l2);
            System.out.println("移除后:" + l1 );
    
            // 判断集合是否为空
            System.out.println(l1.isEmpty( ));
    
            // 存储的元素的个数
            int size = l1.size( );
            System.out.println("集合元素个数:" + size );
    
            // 判断集合是否包含某个元素
            System.out.println(l1.contains(11));
    
            // 先创建整型数组
            Integer[] integers = new Integer[l1.size( )];
            // 再将集合转成数组
            Integer[] array = l1.toArray(integers);
            System.out.println(Arrays.toString(array));
    
            // 清空集合
            l1.clear();
            System.out.println("清空后: " + l1 );
            // 判断集合是否为空
            System.out.println(l1.isEmpty( ));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    3.4 迭代

    集合遍历

    // 使用迭代器遍历

       public static void main(String[] args) {
            /**
             * 使用迭代器遍历
             */
            ArrayList<Integer> list = new ArrayList<>( );
            list.add(4);
            list.add(2);
            list.add(1);
            list.add(3);
    
            // 1)获得迭代器
            Iterator<Integer> iterator = list.iterator();
            // 2)遍历迭代
            while (iterator.hasNext()) {// 判断有无下一个元素,如果有返回true
                Integer next = iterator.next( );// 取出下一个元素
                System.out.println(next );
            }
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    // foreach迭代

        public static void main(String[] args) {
            /**
             * 使用迭代器遍历
             */
            ArrayList<Integer> list = new ArrayList<>( );
            list.add(4);
            list.add(2);
            list.add(1);
            list.add(3);
    
            // 1)获得迭代器
            Iterator<Integer> iterator = list.iterator();
            // 2)遍历迭代
            while (iterator.hasNext()) {// 判断有无下一个元素,如果有返回true
                Integer next = iterator.next( );// 取出下一个元素
                System.out.println(next );
            }
    
            // 迭代器的简化写法: 增强for循环,也叫foreach
            /**
             * for(数据类型 变量 : 集合) {
             *
             * }
             */
            for (Integer i : list) {
                System.out.println(i );
            }
    
            // 遍历数组
            int[] arr = {1,2,3,4};
            for(int i:arr){ // 冒号左边是遍历得到的结果,不是下标!!!
                System.out.println(i);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    3.5 底层原理[面试]

    • ArrayList底层是数组实现的
    • 始容量(数组长度)默认是10
      • 刚new完创建的空集合的,容量是0
      • 当第一次加入元素的时候,数组扩容成10
    • 当元素放满10个时,当加入第11个时候会触发扩容,扩容为原来的1.5倍(通过 >> 1 右移1位算出来)
      • 扩容成1.5倍后,再把原数组的元素拷贝到新数组

    // 扩容的源码 (ArrayList.java(

    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);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    这个函数是用于增长数组容量的。当数组容量不足时,它将根据最小需求容量(minCapacity)来计算新的容量大小,并确保新的容量大于当前需求。若新容量小于需求,则将新容量设置为需求容量。若新容量超过最大数组大小,则调用hugeCapacity方法来处理。最后,通过Arrays.copyOf方法复制原数组到新的容量中。
    
    • 1

    使用上效率问题

    • ArrayList进行元素的 查询,修改速度快
    • 进行元素的,插入和删除速度慢

    原因

    • 数组在内存是连续空间,有下标
    • 所以,通过下标直接定位找到元素,改变该位置元素(查询和更新快)
    • 也是因为内存空间原因,插入或者删除一个数据时,从插入/删除位置开始后续的元素需要后移/前移一位

    四、LinkedList[理解]

    LinkedList也是List实现类,也是允许元素重复,有序的集合

    4.1 方法演示

    LinkedList也是List实现类,大部分方法与ArrayList一模一样用法,不再演示

    自习尝试,

    • 创建LinkedList集合
    • 加入元素
    • foreach变量LinkedList

    4.2 特殊方法

    除了基本的方法与ArrayList一样之外,LinkedList还提供一些比较特殊的操作头尾的方法

    • getFirst getLast
    • removeFirst removeLast
    • addFirst addLast
        public static void main(String[] args) {
    
            LinkedList<Integer> l1 = new LinkedList<>( );
            l1.add(11);
            l1.add(22);
            l1.add(33);
    
            // 获得头 尾操作
            Integer first = l1.getFirst( );
            Integer last = l1.getLast( );
            System.out.println(first );
            System.out.println(last );
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.3 底层原理

    LinkedList底层是双向链表

    • 链表在内存中是不连续
    • 通过链域里面记录上一个/下一个元素的位置

    image-20240308163027261

    当通过下标找寻一个元素的时候,并不是直接定位的,是从头或者尾开始一个一个遍历查找对应的元素,也正是因为如此,所以提供了专门操作头尾的方法的,可以直接定位到,方便操作

    又因为这个空间数据结构问题,导致了一些特性

    • LinkedList查询,更新数据慢
    • LinkedList插入,删除的快
      • 因为插入/删除元素改变的知识链域的记录信息,没有改变其他元素位置

    五、总结

    • 记住集合体系的各自特点
    • 牢记ArrayList方法,底层原理
    • LinkedList了解原理
  • 相关阅读:
    MySQL Server 和 MySQL Workbench安装
    PMP考试通关宝典-敏捷专题
    【Sa-Token|3】Sa-Token集成到现有微服务详细介绍
    嵌入式linux学习笔记---tar多核压缩
    实现定时器的两种方法:使用windows api定时器 和使用c++11/14 定时器
    AQS层层剖析
    PHP+Redis+Lua 实现 Redis 分布式锁
    基金管理人公司治理和风险管理
    从 160 万到 1.5 亿美元 ,开源软件迎来融资热潮
    Vue3学习——pinia
  • 原文地址:https://blog.csdn.net/weixin_39641494/article/details/136581237