day15_集合md

本文详细介绍了Java中的throw和throws关键字区别,以及集合框架中的ArrayList和LinkedList,包括它们的底层实现、操作方法、泛型应用和迭代机制。着重讨论了数组与集合的不同,以及LinkedList特有的头部和尾部操作特点。
摘要由CSDN通过智能技术生成

复习

throw和throws的区别

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

一、集合框架体系

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

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

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

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

注:实线是继承,虚线是实现

在这里插入图片描述

  • Collection是集合层次的父接口,定义了所有集合共性操作
  • Collection有两个常用子接口:List(有序、重复集合)、Set(去重的集合)
    • List接口有两个常用实现类:ArrayList(底层是数组)、LinkedList(底层是双向链表)
    • Set接口有两个常用实现类:HashSet(底层是Hash表,无序去重)、TreeSet(底层是红黑二叉树,去重排序)

二、Collection、List介绍

  • Collection父接口
    • 定义了一部分集合的共性操作,并不会
  • List是Collection的子接口,有序允许重复的集合
    • 定义了一些方法,可以对位置进行精准控制
    • 即可以按照下标插入,删除,查询,修改集合元素
  • List是接口,不能直接用,常用使其子实现类,ArrayList和LinkedList

三、ArrayList

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

3.1方法演示1

  • 初始化集合
        ArrayList list = new ArrayList();
  • list.add(E e);向末尾添加元素,有序(插入顺序),允许重复,可以存储不同类型

  • list.add(index i,E e);向指定下标插入数据

  • Object o = list.get(index i);获得指定下标的元素

  • list.set(index i,E e);按照下标修改元素

  • Object old = list.remove(index i)按照下标删除元素,返回值是要删除的元素

演示示例:

public static void main(String[] args) {
        ArrayList list = new ArrayList();
        System.out.println("初始化:"+list);
        //在集合中末尾添加元素
        //有序(插入顺序),允许重复,允许存储不同类型
        list.add(2);
        list.add(4);
        list.add("3");
        list.add(27);
        System.out.println("添加值后:"+list);
        //指定下标插入元素
        list.add(2,7);
        System.out.println("中间插入后的集合列表:"+list);

        //获得指定下标的元素,返回值类型是Object类
        Object o = list.get(2);
        System.out.println("获得指定下标元素:"+o);

        //按照下标修改元素
        list.set(2,19);
        System.out.println("下标修改后:"+list);

        //按照下标删除元素
        Object old = list.remove(3);
        System.out.println("要删除的元素:"+old);
        System.out.println("删除后的集合:"+list);
    }

3.2泛型

设置原因:

  • 集合本身可以存储不同类型,但是有时候会想要使用一种类型,还要强制转换,但转换也有可能会出现失败
  • 泛型样式:<>中就是要指定的类型
        ArrayList<Integer> list1 = new ArrayList<>();

作用:

  • 泛型来定义集合,在类名后,指定泛型类型,从而确定该集合只能存储指定类型
  • 好处:减少类型转换(强转)

演示有泛型的增、删、改、查示例:

public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        //添加指定类型的集合
        list.add(2);
        list.add(4);
        list.add(5);
        System.out.println("添加值后:"+list);

        //指定下标存放元素
        list.add(3,6);
        System.out.println("指向下标添加后:"+list);

        //指定下标删除元素,
        //由于设置了泛型,返回值就是指定类型而不是Object类型
        Integer old = list.remove(4);
        System.out.println("要删除的元素:"+old);
        System.out.println("删除后的集合:"+list);

        //指定下标修改元素
        list.set(2,46);
        System.out.println("指定下标修改后的集合:"+list);
    }

以后,凡是用

3.3方法演示2

  • list.addAll(Collection lis); 批量添加,将一个集合添加到用一个集合中
  • list.removeAll(Collection lis); 异常当前集合中,存在于参数集合相同的元素
  • list.isEmpty(); 判断是否为空,返回值是布尔型
  • int size = list.size(); 存储元素的个数
  • list.clear(); 清空集合
  • list.contains(E e); 判断集合是否包含指定元素,返回值是布尔型
  • Object[] o = list.toArray(); 转换为数组,虽然指定泛型,但返回值是Object
  • 泛型集合转换为数组,以整型为例
public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(44);
        list.add(33);
        list.add(22);
        list.add(88);
        System.out.println("list添加后的集合:"+list);

        ArrayList<Integer> list1 = new ArrayList<>();
        list1.add(56);
        list1.add(34);
        list1.add(677);
        list1.add(433);
        System.out.println("添加后的list1"+list1);

        //将list1中的所有元素添加到list,addAll() 批量添加
        list.addAll(list1);
        System.out.println("添加后的list:"+list);

        //批量删除
        list.removeAll(list1);
        System.out.println("批量删除list1集合之后:"+list);

        //判断是否为空
        System.out.println(list.isEmpty());

        //求集合中元素的个数
        int size = list1.size();
        System.out.println(size);

        //判断集合中是否包含某个元素
        System.out.println(list.contains(33));

        //转换为数组
        Object[] array1 = list1.toArray();
        System.out.println("转换为Object类型数组:"+ Arrays.toString(array1));

        // 转为规定数据类型的数组
        //先创建整型数组
        Integer[] integers = new Integer[list.size()];
        Integer[] array = list.toArray(integers);
        System.out.println("转换为数组:"+Arrays.toString(array1));
    }

3.4迭代

        //获得迭代器
        Iterator<Integer> iterator = list.iterator();
        //遍历迭代
        while (iterator.hasNext()){  // 判断有无下一个元素
            Integer next = iterator.next(); // 有就取出
            System.out.println(next);
        }

迭代器的简化写法:增强for循环,也叫foreach

        // for(数据类型  变量 : 集合){}
        //遍历数组
        int[] arr = {1,2,3,4};
        for (int i : arr) {
            System.out.println(i);
        }

3.5底层原理[面试]

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

代码展示扩容原理:

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);
    }

使用上效率问题

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

原因

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

四、LinkedList

4.1方法演示

LinkedList也是List实现类,大部分方法和ArrayList一模一样用法

 public static void main(String[] args) {
        LinkedList<Integer> integers = new LinkedList<>();
        integers.add(97);
        integers.add(67);
        integers.add(923);
        integers.add(97);

        LinkedList<Integer> integers1 = new LinkedList<>();
        integers1.add(11);
        integers1.add(22);
        integers1.add(33);
        integers1.add(44);

        //批量添加
        integers.addAll(integers1);
        System.out.println("批量添加后的:"+integers);
        System.out.println("-----------------");

        //批量删除
        integers.removeAll(integers1);
        System.out.println("批量删除后:"+integers);
        
        //修改
        integers.set(3,567);
        System.out.println("修改后:"+integers);

        //迭代
        for (Integer integer : integers) {
            System.out.println(integer);
        }
    }

4.2特殊方法

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

  • getFirst getLast ----->获得头/尾元素
  • removeFirst removeLast ------>删除头/尾元素
  • addFirst addLast ------>在头/尾添加元素

4.3底层原理

LinkedList底层是双向链表

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

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

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

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

练习

//用集合完成,编写一个模拟KTV点歌系统的程序。在程序中,输入0代表添加歌曲,输入1代表将所选歌曲置顶,输 入2代表将所选歌曲提前一位,输入3代表退出该系统

public static void main(String[] args) {
        System.out.println("-----------------------欢迎来到点歌系统---------------------");
        System.out.println("0.添加歌曲至列表");
        System.out.println("1.将歌曲置顶");
        System.out.println("2.将歌曲前移一位");
        System.out.println("3.退出");
        LinkedList<String> songs = new LinkedList<>();
        songs.add("伶人");
        songs.add("勇气");
        songs.add("红豆");
        songs.add("胡广生");
        songs.add("岁岁");
        System.out.println("初始化歌曲列表:"+songs);
        while (true){
            System.out.println();
            Scanner scanner = new Scanner(System.in);
            System.out.print("请选择要执行的操作序号:");
            int select = scanner.nextInt();
            switch (select){
                case 0:
                    // addSongs添加上歌曲
                    System.out.print("请输入要添加的歌曲名称:");
                    String addSong = scanner.next();
                    if (songs.contains(addSong)){
                        System.out.println("已经有该歌曲"+addSong);
                        break;
                    }else {
                        songs.add(addSong);
                        System.out.println("已添加歌曲:"+addSong);
                        System.out.println("当前歌曲列表:"+songs);
                        break;
                    }
                case 1:
                    // firstSongs添加上歌曲
                    System.out.print("请输入要置顶的歌曲名称:");
                    String firstSong = scanner.next();
                    if (songs.contains(firstSong)){
                        songs.addFirst(firstSong);
                        System.out.println("已将歌曲"+firstSong+"置顶");
                        System.out.println("当前歌曲列表:"+songs);
                        break;
                    } else {
                        System.out.println("不存在该歌曲");
                        break;
                    }
                case 2:
                    // removeSongs添加上歌曲
                    System.out.print("请输入要提前一位的歌曲名称:");
                    String removeSong = scanner.next();
                    if (songs.contains(removeSong)){
                        int index = songs.indexOf(removeSong);
                        if (index == 0){
                            System.out.println("该歌曲已置顶,无法前进一位");
                            break;
                        } else {
                            songs.remove(removeSong);
                            songs.add(index-1,removeSong);
                            System.out.println("已将歌曲"+removeSong+"提前一位");
                            System.out.println("当前歌曲列表:"+songs);
                            break;
                        }
                    } else {
                        System.out.println("不存在该歌曲");
                        break;
                    }
                case 3:
                    System.out.println("-----------------退出---------------------");
                    System.out.println("您已退出系统");
                    exit(0);
                    break;
                default:
                    System.out.println("请输入正确格式!");
                    break;
            }
        }
    }
  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值