54_集合类库(上)

article/2025/4/20 20:13:26

集合类库(上)

集合的概述(重点)

  1. 集合的由来

    • 当需要在Java程序中记录单个数据内容时,则声明一个变量,本质就是在内存中申请一个小格子,把数据塞进去。
    • 当需要在Java程序中记录多个类型相同的数据内容时,声明一个一维数组,一段连续的存储单元,把它分成很多个小格子,每个小格子都能存放一个数据内容。 缺陷:必须放同类型的数据。
    • 当需要在Java程序中记录多个类型不同的数据内容时,则创建一个对象
    • 当需要在Java程序中记录多个类型相同的对象数据时,创建一个对象数组
    • 当需要在Java程序中记录多个类型不同的对象数据时,则准备一个集合
  2. 集合的框架结构

  • Java中集合框架顶层框架(2个)是:java.util.Collection集合 和 java.util.Map集合。

  • 其中Collection集合中存取元素的基本单位是:单个元素

  • 其中Map集合中存取元素的基本单位是:单对元素

    在这里插入图片描述

Collection集合(重点):容器集合

  1. 基本概念:java.util.Collection接口是List接口、Queue 接口以及Set接口父接口,因此该接口里定义的方法既可用于操作List集合,也可用于操作Queue集合和Set集合

  2. 常用的方法(练熟、记住)

    方法声明功能介绍
    boolean add(E e); E暂时看作Object类型向集合中添加对象
    boolean addAll(Collection c)用于将参数指定集合c中的所有元素添加到当前集合 中
    boolean contains(Object o);判断是否包含指定对象
    boolean containsAll(Collection c)判断是否包含参数指定的所有对象
    boolean retainAll(Collection c)保留当前集合中存在且参数集合中存在的所有对象
    boolean remove(Object o);从集合中删除对象
    boolean removeAll(Collection c)从集合中删除参数指定的所有对象
    void clear();清空集合
    int size();返回包含对象的个数
    boolean isEmpty();判断是否为空
    boolean equals(Object o)判断是否相等
    int hashCode()获取当前集合的哈希码值
    Object[] toArray()将集合转换为数组
    Iterator iterator()获取当前集合的迭代器
  3. **笔试考点:**c1.add(c2); 和 c1.addAll(c2);两种方式有何区别?效果区别:有无[]

    // 将c2中的所有元素全部添加到集合c1中,也就是将集合c2中的元素一个一个依次添加到集合c1中
    b1 = c1.addAll(c2);
    // 表示将集合c2整体看做一个元素添加到集合c1中
    //b1 = c1.add(c2);
    // 笔试考点:c1.add(c2); 和 c1.addAll(c2);两种方式有何区别?效果区别:有无[]
    System.out.println("b1 = " + b1);
    // [one, 2, Person{name='zhangfei', age=30}, three, 4]    [one, 2, Person{name='zhangfei', age=30}, [three, 4]]
    System.out.println("c1 = " + c1);
    
    package com.huang.task04;import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.List;public class CollectionTest {public static void main(String[] args) {// 1.准备一个Collection集合并打印//Collection c1 = new Collection();  // 接口不能实例化,也就是不能创建对象// 接口类型的引用指向实现类的对象,形成了多态  多态的第二种场合Collection c1 = new ArrayList();// 自动调用toString方法,调用ArrayList类中的toString方法,默认打印格式为:[元素值1, 元素值2, ...]// 多态编译阶段调父类,运行阶段调子类System.out.println("集合中的元素有:" + c1); // [啥也没有]System.out.println("--------------------------------------------------------");// 2.向集合中添加单个元素并打印boolean b1 = c1.add(new String("one"));System.out.println("b1 = " + b1); // true  b1的值决定我们是否添加成功System.out.println("集合中的元素有:" + c1); // [one]b1 = c1.add(Integer.valueOf(2));System.out.println("b1 = " + b1); // trueSystem.out.println("集合中的元素有:" + c1); // [one, 2]b1 = c1.add(new Person("zhangfei", 30));System.out.println("b1 = " + b1); // true// 打印集合中的所有元素时,本质上就是打印集合中的每个对象,也就是让每个对象调用对应类的toString方法System.out.println("集合中的元素有:" + c1); // [one, 2, Person{name='zhangfei', age=30}]System.out.println("--------------------------------------------------------");// 3.向集合中添加多个元素并打印Collection c2 = new ArrayList();c2.add("three");  // 常量池c2.add(4);        // 自动装箱机制System.out.println("c2 = " + c2); // [three, 4]// 将c2中的所有元素全部添加到集合c1中,也就是将集合c2中的元素一个一个依次添加到集合c1中b1 = c1.addAll(c2);// 表示将集合c2整体看做一个元素添加到集合c1中//b1 = c1.add(c2);// 笔试考点:c1.add(c2); 和 c1.addAll(c2);两种方式有何区别?效果区别:有无[]System.out.println("b1 = " + b1);// [one, 2, Person{name='zhangfei', age=30}, three, 4]    [one, 2, Person{name='zhangfei', age=30}, [three, 4]]System.out.println("c1 = " + c1);System.out.println("--------------------------------------------------------");// 4.判断集合中是否包含参数指定的单个元素// boolean contains(Object o);  Object类型作为形参变量的类型,那么我们所传的实参可以是任意类型的变量,只要是个对象都可以传,大不了构成多态// boolean类型的返回值代表是否包含,包含返回true,不包含返回false// c1:[one, 2, Person{name='zhangfei', age=30}, three, 4]b1 = c1.contains(new String("one")); // new 不new都可以,区别在于new出来的是两个对象,不new的话只有一个对象在常量池System.out.println("b1 = " + b1); // trueb1 = c1.contains(new String("two"));System.out.println("b1 = " + b1); // falseb1 = c1.contains(Integer.valueOf(2));System.out.println("b1 = " + b1); // trueb1 = c1.contains(Integer.valueOf(3));System.out.println("b1 = " + b1); // false// contains方法的工作原理是:Objects.equals(o, e),其中o代表contains方法的形式参数,e代表集合中的每个元素// 也就是contains的工作原理就是 拿着参数对象与集合中已有的元素依次进行比较,比较的方式调用Objects中的equals方法// 而该方法equals的工作原理如下:/*public static boolean equals(Object a, Object b) {    其中a代表Person对象,b代表集合中已有的对象return (a == b) || (a != null && a.equals(b));元素包含的第一种方式就是:Person对象与集合中已有对象的地址相同第二种方式就是:Person对象不为空,则Person对象调用equals方法与集合中已有元素相等}*/// 当Person类中没有重写equals方法时,则调用从Object类中继承下来的equals方法,比较两个对象的地址  false// 当Person类中重写equals方法后,则调用重写以后的版本,比较两个对象的内容  trueb1 = c1.contains(new Person("zhangfei", 30));System.out.println("b1 = " + b1); // true  falseSystem.out.println("--------------------------------------------------------");// [one, 2, Person{name='zhangfei', age=30}, three, 4]System.out.println("c1 = " + c1);// 5.判断当前集合中是否包含参数指定集合的所有元素Collection c3 = new ArrayList();c3.add(4);System.out.println("c3 = " + c3); // [4]// 判断集合c1中是否包含集合c3中的所有元素b1 = c1.containsAll(c3);System.out.println("b1 = " + b1); // truec3.add("five");System.out.println("c3 = " + c3); // [4, five]// 判断集合c1中是否包含集合c3中的所有元素,只有集合c3中的所有元素都在集合c1中出现才会返回true,否则都是falseb1 = c1.containsAll(c3);System.out.println("b1 = " + b1); // false// 笔试考点System.out.println("c2 = " + c2); // [three, 4]b1 = c1.containsAll(c2); // 上方调用的是addAll方法System.out.println("b1 = " + b1); // true false// 判断集合c1中是否拥有集合c2这个整体为单位的元素b1 = c1.contains(c2); // 上方是add方法// 也就是说:上方添加的是个整体,就可以使用contains方法判断出来。上方如果是调用addAll将c2中的元素一个个的加入到c1中,我们就只有使用containsAll方法时才返回trueSystem.out.println("b1 = " + b1); // false trueSystem.out.println("--------------------------------------------------------");// 6.计算两个集合的交集并保留到当前集合中// retainAll 方法也就是保留隐式参数的集合中有且形式参数传过来的集合中也有的值,也就是取两个集合中的交集并保留到隐式参数集合中// 返回值boolean根据官方手册来说:只要调用方法的集合发生了改变就返回true,否则就是falseSystem.out.println("c2 = " + c2); // [three, 4]System.out.println("c3 = " + c3); // [4, five]// 也就是让集合自己和自己取交集,还是自己,也就是当前集合中的元素没有发生改变b1 = c2.retainAll(c2);System.out.println("b1 = " + b1); // false 表示当前集合中的元素没有发生改变System.out.println("c2 = " + c2); // [three, 4]// 计算集合c2和c3的交集并保留到集合c2中,取代集合c2中原有的数值b1 = c2.retainAll(c3);System.out.println("b1 = " + b1); // true 当前集合的元素发生了改变System.out.println("c2 = " + c2); // [4]System.out.println("c3 = " + c3); // [4, five]System.out.println("--------------------------------------------------------");// 7.实现集合中单个元素的删除操作// [one, 2, Person{name='zhangfei', age=30}, three, 4]System.out.println("c1 = " + c1);// 删除参数指定的单个元素b1 = c1.remove(1);System.out.println("b1 = " + b1); // false// [one, 2, Person{name='zhangfei', age=30}, three, 4]System.out.println("c1 = " + c1);b1 = c1.remove("one");System.out.println("b1 = " + b1); // true// [2, Person{name='zhangfei', age=30}, three, 4]System.out.println("c1 = " + c1);// remove方法的工作原理:Objects.equals(o, e),原理和contains方法一致b1 = c1.remove(new Person("zhangfei", 30));System.out.println("b1 = " + b1); // true// [2, three, 4]System.out.println("c1 = " + c1);System.out.println("--------------------------------------------------------");// 8.实现集合中所有元素的删除操作System.out.println("c3 = " + c3); // [4, five]// 从集合c1中删除集合c3中的所有元素,本质上就是一个一个元素进行删除,有元素则删除,否则不删除b1 = c1.removeAll(c3); // 只要集合造成了改变就返回trueSystem.out.println("b1 = " + b1); // true// [2, three]System.out.println("c1 = " + c1);System.out.println("c3 = " + c3); // [4, five]// 笔试考点  删除整体对象c3  如何删除单个对象和多个对象b1 = c1.remove(c3);System.out.println("b1 = " + b1); // false 没得删System.out.println("c1 = " + c1); // [2, three]// 修改操作:先使用remove方法进行删除,然后再使用add方法进行添加就完成了修改操作。System.out.println("--------------------------------------------------------");// 9.实现集合中其它方法的测试   ctrl+n 可以直接搜索并打开类的源码  使用ctrl+f12可以搜索类中的方法System.out.println("集合中元素的个数为:" + c1.size()); // 2System.out.println(0 == c1.size() ? "集合已经空了": "集合还没有空"); // 没有空System.out.println(c1.isEmpty()? "集合已经空了": "集合还没有空"); // 没有空// 清空集合中的所有元素c1.clear();System.out.println("集合中元素的个数为:" + c1.size()); // 0System.out.println(0 == c1.size() ? "集合已经空了": "集合还没有空"); // 已经空了System.out.println(c1.isEmpty()? "集合已经空了": "集合还没有空");   // 已经空了// size()方法和isEmpty()方法有点重叠。结果都一样,因为二者都依赖与成员变量size/*** 快捷键:ctrl+n 可以直接搜索并打开类的源码  使用ctrl+f12可以搜索类中的方法** public boolean isEmpty() {*     return size == 0;* }**  public int size() {*     return size;* }** hashCode对现在的我们来说没啥用就是为了保证和equals的一致性*/// 准备两个集合并判断是否相等Collection c4 = new ArrayList();c4.add(1);c4.add(2);System.out.println("c4 = " + c4); // [1, 2]Collection c5 = new ArrayList();c5.add(1);c5.add(2);c5.add(3);System.out.println("c5 = " + c5); // [1, 2, 3]// 判断是否相等b1 = c4.equals(c5);System.out.println("b1 = " + b1); // true  false// true的时候没有c5.add(3);即:那时c5还是[1, 2]System.out.println("--------------------------------------------------------");// 10.实现集合和数组类型之间的转换   通常认为:集合是用于取代数组的结构// 数组的缺点:长度固定不可变,进行增删操作可能会移动大量的元素效率很低下。集合可以弥补数组的这些缺点。// 实现集合向数组类型的转换Object[] objects = c5.toArray();// 打印数组中的所有元素System.out.println("数组中的元素有:" + Arrays.toString(objects)); // [1, 2, 3]// 实现数组类型到集合类型的转换Collection objects1 = Arrays.asList(objects); // asList方法将数组类型转换为集合System.out.println("集合中的元素有:" + objects1); // [1, 2, 3]}
    }

Iterator接口(重点)

  1. 基本概念

    • 迭代:今天的学的内容可能运用到昨天所学的内容。

    • java.util.Iterator接口主要用于描述迭代器对象,可以遍历Collection集合中的所有元素。 遍历就是把集合中的所有元素一个一个的取出来打印。

    • java.util.Collection接口继承Iterable接口(也就是Collection接口的所有子接口或者实现类都继承或实现了Iterator接口),因此所有实现Collection接口的实现类子接口都可以使用该迭代器对象

    • 工作原理图解:

      在这里插入图片描述
      在这里插入图片描述

  2. 常用的方法:配合使用hasNext方法和next

    方法声明方法声明
    boolean hasNext()判断集合中是否有可以迭代/访问的元素
    E next()用于取出一个元素并指向下一个元素
    void remove()用于删除访问到的最后一个元素,next访问到谁,我们就删除谁
  3. 案例题目:

    如何使用迭代器实现toString方法的打印效果?

    // 由于上个循环已经使得迭代器走到了最后,因此需要重置迭代器
    iterator1 = c1.iterator(); // 重置迭代器
    // 3.使用迭代器来模拟toString方法的打印效果
    StringBuilder sb1 = new StringBuilder();
    // 下面代码和ArrayList的toString方法十分类似
    sb1.append("[");
    while (iterator1.hasNext()) {Object obj = iterator1.next();// 当获取的元素是最后一个元素时,则拼接元素加中括号if (!iterator1.hasNext()) {sb1.append(obj).append("]");} else {// 否则拼接元素加逗号加空格sb1.append(obj).append(",").append(" ");}
    }
    // [one, 2, Person{name='zhangfei', age=30}]
    System.out.println("c1 = " + sb1);
    
    package com.huang.task04;import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.Iterator;public class CollectionPrintTest {public static void main(String[] args) {// 1.准备一个Collection集合并放入元素后打印Collection c1 = new ArrayList();c1.add("one");c1.add(2);c1.add(new Person("zhangfei", 30));// 遍历方式一: 自动调用toString方法   得到的是一个String类型的整体System.out.println("c1 = " + c1.toString()); // [one, 2, Person{name='zhangfei', age=30}]System.out.println("------------------------------------------------");// 2.遍历方式二:使用迭代器来遍历集合中的所有元素  优势:更加灵活// 2.1 获取当前集合中的迭代器对象Iterator iterator1 = c1.iterator();/*// 2.2 判断是否有元素可以访问System.out.println(iterator1.hasNext()); // true// 2.3 取出一个元素并指向下一个System.out.println("获取到的元素是:" + iterator1.next()); // oneSystem.out.println(iterator1.hasNext()); // trueSystem.out.println("获取到的元素是:" + iterator1.next()); // 2System.out.println(iterator1.hasNext()); // trueSystem.out.println("获取到的元素是:" + iterator1.next()); // Person{name='zhangfei', age=30}System.out.println(iterator1.hasNext()); // falseSystem.out.println("获取到的元素是:" + iterator1.next()); // 编译ok,运行发生NoSuchElementException没有这样的元素异常*/while (iterator1.hasNext()) {System.out.println("获取到的元素是:" + iterator1.next());}System.out.println("------------------------------------------------");// 由于上个循环已经使得迭代器走到了最后,因此需要重置迭代器iterator1 = c1.iterator(); // 重置迭代器// 3.使用迭代器来模拟toString方法的打印效果StringBuilder sb1 = new StringBuilder();// 下面代码和ArrayList的toString方法十分类似sb1.append("[");while (iterator1.hasNext()) {Object obj = iterator1.next();// 当获取的元素是最后一个元素时,则拼接元素加中括号if (!iterator1.hasNext()) {sb1.append(obj).append("]");} else {// 否则拼接元素加逗号加空格sb1.append(obj).append(",").append(" ");}}// [one, 2, Person{name='zhangfei', age=30}]System.out.println("c1 = " + sb1);System.out.println("------------------------------------------------");// 4.不断地去获取集合中的元素并判断,当元素值为"one"时则删除该元素iterator1 = c1.iterator(); // 重置迭代器while (iterator1.hasNext()) {Object obj = iterator1.next();if("one".equals(obj)) {iterator1.remove();  //使用迭代器的remove方法删除元素没问题//c1.remove(obj); // 使用集合的remove方法编译ok,运行发生ConcurrentModificationException并发修改异常// 使用集合的add方法编译ok,运行发生ConcurrentModificationException并发修改异常// 如果我们正在迭代一个集合的时候我们不允许有人去修改它,因为这样迭代出来的结果是不确定的。// 会不会抛出异常会不会错取决于是否在迭代过程中调用了集合中的方法,如果是在迭代过程中调用的删除方法,就要使用迭代器的,否则容易发生并发修改异常}}System.out.println("删除后集合中的元素有:" + c1); // [2, Person{name='zhangfei', age=30}]}
    }

for each循环(重点)

  1. 基本概念

    • Java5推出了增强型for循环语句,可以应用数组和集合的遍历。
    • 是经典迭代的“简化版”。
  2. 语法格式

    • for(元素类型 变量名 : 数组/集合名称) {   数组或集合的数据类型  变量名随便起循环体;
      }
      
  3. 执行流程

    • 自动地不断地从数组/集合中取出一个元素赋值给变量名并执行循环体,直到取完所有元素为止。

    • System.out.println("------------------------------------------------");
      // 5.使用 for each结构实现集合和数组中元素的遍历  代码简单且方法灵活,如果以后只是想单纯的打印就使用这种方法
      // 由调试源码可知:该方式确实是迭代器的简化版
      for (Object obj : c1) { // 调试Debug的主要作用:帮注我们观察、理解、分析代码的执行流程// 所谓调试就是让代码一步一步的去执行,让我们更清晰的去看到代码的执行流程,然后去分析我们在代码中的一些逻辑错误或者解决代码的一些其它的错误System.out.println("取出来的元素是:" + obj);
      }int[] arr = new int[] {11, 22, 33, 44, 55};
      for (int i : arr) { // for-each只是用来遍历输出的并不能对数组中的元素进行修改System.out.println("i = " + i);i = 66; // 修改局部变量i的数值,并不是修改数组中元素的数值
      }
      System.out.println("数组中的元素有:" + Arrays.toString(arr));
      

List集合(重中之重)

  1. 基本概念:特点:有序,可重复

    • java.util.List(接口)集合是Collection集合的子集合,该集合中允许有重复的元素并且有先后放入次序

    • 该集合的主要实现类有:1、ArrayList类、2、LinkedList类、3、Stack类、4、Vector类。

    • 其中ArrayList类的==底层是采用动态数组(它内部封装实现了自动扩容功能)==进行数据管理的,依次插入数据,支持下标访问,故而访问方便,增删元素不方便(详情看数组)在这里插入图片描述

      // 1.声明一个List接口类型的引用指向ArrayList类型的对象,形成了多态
      // 由源码可知:当new对象时并没有申请数组的内存空间
      /*** ArrayList的底层原理:我们new对象的时候不给申请内存空间,只赋值为一个空数组* 第一次add的时候再申请一个长度为10的一维数组,如果需要扩容的时候,我们会扩容为之前数组大小的1.5倍*/
      List lt1 = new ArrayList();
      /*** 写这代码的原因是为了解分析ArrayList类的工作原理,以及它的执行流程需要使用Debug方式* 从List lt1 = new ArrayList();进入源码中第一次进入的是类加载过程,我们需要跳出源码再进去** 底层原理:无参构造流程* 拿着常量给成员变量初始化赋值* 在ArrayList的底层实际上声明了一个Object类型的一维数组负责将我们所有的元素保存起来* 验证了一点:ArrayList的底层真的是一维数组* transient Object[] elementData;** 下面这个实际上就是一个Object类型的一维空数组* private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};** private int size; 使用size来记录ArrayList中存放的元素个数的** public ArrayList() {*      一开始我们就是拿着一维空数组来给成员变量进行初始化*      也就是说我们在new ArrayList的对象时我们并没有立刻去给ArrayList申请内存空间*      实际上就只是一个空的数组来初始化*      数组的长度为0说明并没有为数组申请内存空间*     this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;* }*/
      // 2.向集合中添加元素并打印
      // 由源码可知:当调用add方法添加元素时会给数组申请长度为10的一维数组,扩容原理是:原始长度的1.5倍
      lt1.add("one");
      /*** 底层扩容原理:* public boolean add(E e) { 这里面的 e 的值是调用add方法传入的实参"one"*     modCount++; 这个暂时用不上,先不管它*     add(e, elementData, size); size = 0 e = "one" 这个说明要把元素e的值放到数组elementDate中数组长度为0*     return true;  这里说明了无论添加哪个元素,这里返回的都是true,始终返回true,也就说明了之前的代码为什么没有失败的原因了* }** private void add(E e, Object[] elementData, int s) {*     if (s == elementData.length)*         elementData = grow(); grow方法就是用来增长开辟内存的*     elementData[s] = e; 把传过来的数值放到数组中下标为s的位置,0*     size = s + 1;* }** private Object[] grow() {*     return grow(size + 1); size最开始是0,然后+1,就变成了1* }** private Object[] grow(int minCapacity) { minCapacity = 1,要放一个元素进来,说明最小容量是1*     return elementData = Arrays.copyOf(elementData,*                                        newCapacity(minCapacity));  将原始数组中的内容拷贝到新的数组,新的数组首先得申请新的内存空间* }** private static final int DEFAULT_CAPACITY = 10; 默认初始容量** 看内部到底如何申请内存,机制到底如何* private int newCapacity(int minCapacity) { 申请内存空间*     // overflow-conscious code*     int oldCapacity = elementData.length;    oldCapacity = 数组的长度,此时是0*     int newCapacity = oldCapacity + (oldCapacity >> 1);  新的内存空间的大小 = 旧的内存空间的大小 + 旧的内存空间大小右移一位(左移一位 * 2,右移一位 / 2)*     也就是说:新的内存空间大小 = 1.5倍旧的内存空间大小 , 扩容为原始数组长度的1.5倍*     if (newCapacity - minCapacity <= 0) { 0 - 1 <= 0*         if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)*             return Math.max(DEFAULT_CAPACITY, minCapacity);  在10和1之间取二者最大值,此处是DEFAULT_CAPACITY, 也就是 10*         if (minCapacity < 0) // overflow*             throw new OutOfMemoryError();*         return minCapacity; return DEFAULT_CAPACITY; = return 10;*     }*     return (newCapacity - MAX_ARRAY_SIZE <= 0)*         ? newCapacity*         : hugeCapacity(minCapacity);* }*/
      System.out.println("lt1 = " + lt1); // [one]
      
    • 其中LinkedList类的==底层是采用双向链表(双向链表表示从前到后能找着,从后向前也能找着)==进行数据管理的,访问不方便,增删元素方便。 为了存放下面的5个数据,我们必须给每个数据申请一个独立的内存空间,每个蓝色的小框框都是一个节点,每个节点不仅存储了当前节点的数据,还存储了它的前驱节点的内存地址和后继节点的内存地址。(好处:找到10以后,可以根据里面存放的后继元找到20…以此类推,我们找到50之后可以根据前驱元找到40…)红色的线都是内存地址的指向,故而可以看出,该内存结构并不是连续存放数据的。第一个节点没有前驱节点,最后一个节点没有后继节点。

    • 访问不方便:因为内存空间不是连续的,不支持下标访问,找东西必须从后往前一个一个的找,或者从前往后一个一个的找在这里插入图片描述

      System.out.println("----------------------------------------------------");
      // 2.声明一个List接口类型的引用指向LinkedList类型的对象,形成了多态
      List lt2 = new LinkedList();
      /*** 源码解析:* 构造方法里面啥都没有,也就是构造了一个空的链表* 此处啥也没干,没有元素,size也就等于0* public LinkedList() {* }** LinkedList 中有三个成员:*transient int size = 0; 记录元素个数的**transient Node<E> first; 记录第一个节点的地址**transient Node<E> last; 记录最后一个节点的地址** 通过first节点可以从前往后遍历,通过last可以从后往前遍历。也就是双向链表之间已经相互联结起来了,但是我们得记录第一个和最后一个节点。*/
      lt2.add("one");
      /*** 原理解析和原理解析:* public boolean add(E e) { 此时e = "one"*     linkLast(e);  往后链接的意思,也就是为什么有先后放的原因:因为每次我们都往后边放*     return true; 无论该方法的结果是什么,我们都默认返回一个true.* }** Links e as last element.* void linkLast(E e) {*     final Node<E> l = last; 首先申请一个Node类型的引用,让它的值 = last,last指向哪,l就指向哪*     final Node<E> newNode = new Node<>(l, e, null); 创建了一个新的Node,也就是创建了一个新的节点,l是前驱元(此时还是null),e是元素值,null是后继元*     last = newNode;  让last指向newNode,也就是让它作为最后一个节点,last是指向最后一个节点*     if (l == null)*         first = newNode; 如果l为null的时候,此时链表中只有一个节点,便让第一个节点first也指向newNode*         此时它既是首节点也是尾结点*     else*         l.next = newNode; 否则就是之前最后一个节点的后继元也指向newNode*     size++; 元素 + 1*     modCount++;* }** 一个静态内部类作为节点类* private static class Node<E> {*         E item;*         Node<E> next; 下一个:后继元*         Node<E> prev; 上一个:前驱元**         Node(Node<E> prev, E element, Node<E> next) {*             this.item = element;*             this.next = next;*             this.prev = prev;*         }*     }*/
      System.out.println("lt2 = " + lt2); // [one]
      
    • 可以认为ArrayList和LinkedList的方法在逻辑上完全一样,只是在性能上有一定的差别,ArrayList 更适合于随 机访问而LinkedList更适合于插入和删除;在性能要求不是特别苛刻的情形下可以忽略这个差别,取决于以后开发中到底是访问多还是增删多。LinkedList 和 ArrayList 二者间就是一个互补的关系。

    • 其中Stack类的底层是采用动态数组进行数据管理的,该类主要用于描述一种具有后进先出特征的 数据结构,叫做栈(last in first out LIFO)。 这个还是偶尔会用到的。继承自Vector,也基本不用了,从1.0版本开始使用。开发中Stack类已经被Deque接口取代了。

    • 后进先出演示:凡是具有后进先出特点的我们都可以叫做栈,进栈和出栈演示:在这里插入图片描述

    • 在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述在这里插入图片描述
      在这里插入图片描述

    • 其中Vector类的底层是采用动态数组进行数据管理的(已过时:不建议使用了,从Java1.0开始),该类与ArrayList类相比属于线程安全的 类效率比较低以后开发中基本不用。线程安全就意味着效率低,ArrayList类是从Java1.2开始的,后出来的是用来取代Vector的。ArrayList 和 Vector之间的关系有点像之前所说的StringBuilder和StringBuffer之间的关系。

    • 此处提一嘴Vector就是因为笔试中经常会考Vector 和 ArrayList之间的区别,无非就是安全不安全,效率高低区别,且Vector已经被ArrayList取代了。且扩容的时候Vector每次是扩大为2倍,ArrayList每次扩大为1.5倍。只是面试或者笔试会考到,我们需要留意一下就可。

  2. 常用的方法:我们此处值说一些统一的方法,至于各个实现类内部各自的方法自己去API帮助文档中探索和使用一下。增删改查方法都有

    方法声明功能介绍
    void add(int index, E element)向集合中指定位置添加元素
    boolean addAll(int index, Collection c)向集合中指定添加集合中所有元素
    E get(int index)从集合中获取指定位置元素
    int indexOf(Object o)查找参数指定的对象(前->后,第一次出现的位置)
    int lastIndexOf(Object o)反向查找参数指定的对象(后->前,第一次出现的位置)
    E set(int index, E element)修改指定位置的元素,返回值是被修改位置的原有数据
    E remove(int index)删除指定位置的元素,返回值是被删除位置的原有数据
    List subList(int fromIndex, int toIndex)用于获取子List 子集合和当前集合 共用同一块内存空间
    package com.huang.task04;import java.util.LinkedList;
    import java.util.List;public class ListMethodTest {public static void main(String[] args) {// 1.准备一个List集合并打印List lt1 = new LinkedList();System.out.println("lt1 = " + lt1); // [啥也没有]System.out.println("------------------------------------------");// 2.向集合中添加元素并打印// 向集合中的开头位置添加元素lt1.add(0, "one");System.out.println("lt1 = " + lt1); // [one]// 向集合中的末尾位置添加元素lt1.add(1, 3);System.out.println("lt1 = " + lt1); // [one, 3]// 向集合中的中间位置添加元素 现在有2个元素 0 1如果要在中间添加就把1挤到后边变成2,即在1处添加元素 不是覆盖,会把元素向后挤lt1.add(1, "two");System.out.println("lt1 = " + lt1); // [one, two, 3]System.out.println("------------------------------------------");// 3.根据参数指定的下标来获取元素 获取指定位置的元素String str1 = (String) lt1.get(0); // 父类转子类,大到小需要强转,理论上,我们强转的时候需要使用instanceOf进行判断System.out.println("获取到的元素是:" + str1); // one// 注意:获取元素并进行强制类型转换时一定要慎重,因为容易发生类型转换异常// 获取最后一个元素//String str2 = (String)lt1.get(2); // 编译ok,运行发生ClassCastException类型转换异常,引用类型的强制转换必须要有父子类关系//System.out.println("获取到的元素是:" + str2); // 3System.out.println("------------------------------------------");// 4.使用get方法获取集合中的所有元素并打印StringBuilder sb1 = new StringBuilder();sb1.append("[");for (int i = 0; i < lt1.size(); i++) {//Object obj = lt1.get(i);//System.out.println("获取到的元素是:" + obj);Object obj = lt1.get(i);// 若取出的元素是最后一个元素,则拼接元素值和]if (lt1.size()-1 == i) {sb1.append(obj).append("]");}// 否则拼接元素和逗号以及空格else {sb1.append(obj).append(",").append(" ");}}System.out.println("lt1 = " + sb1); // [one, two, 3]System.out.println("------------------------------------------");// 5.查找指定元素出现的索引位置System.out.println("one第一次出现的索引位置为:" + lt1.indexOf("one")); // 0lt1.add("one"); // 没给下标默认添加到末尾System.out.println("lt1 = " + lt1); // [one, two, 3, one]System.out.println("one反向查找第一次出现的索引位置是:" + lt1.lastIndexOf("one")); // 3// 验证了List集合和Collection集合相比,它的独到之处在于:元素可以重复,但是元素有先后放的顺序,先放的在前边,后放的在后边(按索引增加的方法除外)System.out.println("------------------------------------------");System.out.println("lt1 = " + lt1); // [one, two, 3, one]// 6.实现集合中元素的修改Integer it1 = (Integer) lt1.set(2, "three");System.out.println("被修改的元素是:" + it1); // 3System.out.println("修改后集合中的元素有:" + lt1); // [one, two, three, one]String str2 = (String) lt1.set(3, "four");System.out.println("被修改的元素是:" + str2); // oneSystem.out.println("修改后集合中的元素有:" + lt1); // [one, two, three, four]System.out.println("------------------------------------------");// 7.使用remove方法将集合中的所有元素删除//for (int i = 0; i < lt1.size(); /*i++*/) {/* for (int i = lt1.size()-1; i >= 0; i--) {//System.out.println("被删除的元素是:" + lt1.remove(i)); // one  two  three  four 删除元素后,后面的元素补位// 删除元素的时候,size在变小,i在变大,最终 i > size,集合中的元素就删不掉了,讲StringBuilder的时候也说过//System.out.println("被删除的元素是:" + lt1.remove(0)); 此处要把 i++ 去掉,要不i一直在++,而size在--,只能执行2次System.out.println("被删除的元素是:" + lt1.remove(i));}System.out.println("最终集合中的元素有:" + lt1); // [啥也没有]*/System.out.println("------------------------------------------");// 8.获取当前集合中的子集合,也就是将集合中的一部分内容获取出来,子集合和当前集合 共用同一块内存空间// 有点像substring// 表示获取当前集合lt1中下标从1开始到3之间的元素,包含1但不包含3 包含起始不包含结尾List lt2 = lt1.subList(1, 3);System.out.println("lt2 = " + lt2); // [two, three]// 删除lt2中元素的数值// 验证:子集合和当前集合 共用同一块内存空间str2 = (String) lt2.remove(0);System.out.println("被删除的元素是:" + str2); // twoSystem.out.println("删除后lt2 = " + lt2); // [three]System.out.println("删除后lt1 = " + lt1); // [one, three, four]}
    }
  3. 案例题目:这里主要是讲一下栈结构,以后开发中使用Deque来实现

方法声明功能描述
boolean empty()测试此堆栈是否为空。
E peek()查看此堆栈顶部的对象,而不将其从堆栈中删除。
E pop()移除此堆栈顶部的对象,并将该对象作为此函数的值返回。 出栈
E push(E item)将项目推到此堆栈的顶部。 入栈 返回值是要入栈的元素
int search(Object o)返回对象在此堆栈上的从1开始的位置。

准备一个Stack集合,将数据11、22、33、44、55依次入栈并打印,然后查看栈顶元素并打印, 然后将栈中所有数据依次出栈并打印。

再准备一个Stack对象,将数据从第一个栈中取出来放入第二个栈中,然后再从第二个栈中取出并 打印。

package com.huang.task04;import java.util.Stack;public class StackTest {public static void main(String[] args) {// 1.准备一个Stack类型的对象并打印Stack s1 = new Stack();Stack s2 = new Stack();System.out.println("s1 = " + s1); // [啥也没有]System.out.println("s2 = " + s2); // [啥也没有]System.out.println("-----------------------------------------------");// 2.将数据11、22、33、44、55依次入栈并打印for (int i = 1; i <= 5; i++) {Object obj = s1.push(i * 11); // 返回值就是入栈的元素System.out.println("入栈的元素是:" + obj);//System.out.println("栈中的元素有:" + s1); // 11 22 33 44 55// 每来一个元素就放在栈顶,挪在最上面}System.out.println(+s1.search(22)); // 4 索引从1开始,且从栈顶开始往下数的System.out.println("-----------------------------------------------");// 3.查看栈顶元素值并打印//Object obj2 = s1.peek();//System.out.println("获取到的栈顶元素是:" + obj2); // 55System.out.println("-----------------------------------------------");// 4.对栈中所有元素依次出栈并打印int len = s1.size(); // 只读取一次size,读取完就固定了,始终拿着变量的值在用。就是为了防止size减少,i++循环很快结束for (int i = 1; i <= len; i++) {// 在出栈元素的时候也不会改变变量len的值// 一旦涉及到后进的先出这种结构我们就使用栈Object to = s1.pop();//System.out.println("出栈的元素是:" + to); // 55 44 33 22 11 这就叫后进先出s2.push(to);}System.out.println("-----------------------------------------------");// 5.最终打印栈中的所有元素//System.out.println("s1 = " + s1); // [啥也没有]System.out.println("-----------------------------------------------");// 从第二个栈中把元素取出来并打印len = s2.size();for (int i = 1; i <= len; i++) {Object to = s2.pop();System.out.println("出栈的元素是:" + to); // 11 22 33 44 55// 一组数据经过两个栈,入栈的顺序和出栈的顺序一致,也就是说顺序变成了先进先出}}
}

Queue接口(重点)

  1. 基本概念

    • java.util.Queue集合是Collection集合的子集合,与List集合属于平级关系
    • 该集合的主要用于描述具有先进先出特征的数据结构,叫做队列(first in first out FIFO)
    • 该集合的主要实现类是LinkedList类,因为该类在增删方面比较有优势。队列经常需要增加和删除。在这里插入图片描述
      在这里插入图片描述
  2. 常用的方法

    方法声明功能介绍
    boolean offer(E e)将一个对象添加至队尾,若添加成功则返回true 入队
    E poll()从队首删除并返回一个元素 出队
    E peek()返回队首的元素(但并不删除)和栈中一样
  3. 案例题目

    准备一个Queue集合,将数据11、22、33、44、55依次入队并打印,然后查看队首元素并打印, 然后将队列中所有数据依次出队并打印

    package com.huang.task04;import java.util.LinkedList;
    import java.util.Queue;public class QueueTest {public static void main(String[] args) {// 1.准备一个Queue集合并打印Queue queue = new LinkedList();// Stack是个类,所以可以直接new对象,Queue是个接口所以得new实现类的对象System.out.println("队列中的元素有:" + queue); // [啥也没有]System.out.println("----------------------------------------------------------");// 2.将数据11、22、33、44、55依次入队并打印for (int i = 1; i <= 5; i++) {boolean b1 = queue.offer(i * 11);//System.out.println("b1 = " + b1);  返回值是是否入队成功System.out.println("队列中的元素有:" + queue); // 11 22 33 44 55}System.out.println("----------------------------------------------------------");// 3.然后查看队首元素并打印System.out.println("对首元素是:" + queue.peek()); // 11System.out.println("----------------------------------------------------------");// 4.然后将队列中所有数据依次出队并打印int len = queue.size();for (int i = 1; i <= len; i++) {System.out.println("出队的元素是:" + queue.poll()); // 11 22 33 44 55}System.out.println("----------------------------------------------------------");// 5.查看队列中最终的元素System.out.println("队列中的元素有:" + queue); // [啥也没有]}
    }

总结

两个栈也可以实现队列的效果

在这里插入图片描述


http://chatgpt.dhexx.cn/article/vt257ere.shtml

相关文章

[车联网安全自学篇] Android安全之ARM汇编指令集手册「精简汇总版」

也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大 少走了弯路,也就错过了风景,无论如何,感谢经历 0x01 ARM 指令 1.1 ARM架构的CPU简介 PC端领域CPU的老大是Intel,而移动设备CPU老大就是ARM。不同的cpu架构对应不同的指令集…

论文的排版技巧

在任意中间一页开始插入页码 1.在要插入页码的前一页&#xff0c;插入“分页符”&#xff0c;“插入”-->“分隔符”&#xff0c;选择“分节符类型”中的下一页&#xff0c;如图。 2.在要插入页码的页面&#xff0c;选择“视图”-->“页眉与页角” 去掉“链接到前一个的标…

软件开发实训(720科技)――第五课:前端css规范

一、文件规范 1、文件均归档至约定的目录中。 具体要求通过豆瓣的CSS规范进行讲解&#xff1a; 所有的CSS分为两大类&#xff1a;通用类和业务类。通用的CSS文件&#xff0c;放在如下目录中&#xff1a; 基本样式库 /css/core 通用UI元素样式库 /css/lib JS组件相关样式库 …

word 参考文献插入整理

参考文献插入 方法一&#xff1a;使用尾注插入参考文献 1.1. 以尾注的方式插入第一个参考文献 将光标定位于word文档中将要插入参考文献的位置&#xff0c;按“插入/引用/脚注和尾注”。出现一菜单&#xff0c;选择“尾注”&#xff0c;“文档结尾”&#xff0c;编号格式为“1,…

Word 2010如何对论文中参考文献进行标注

Word 2010如何对论文中参考文献进行标注 1.参考文献在论文中进行标注1.1添加标注1.2修改标注“1→[1]” 2.删除参考文献留下的横线3.参考文献对齐参考 在文章中标注参考文献&#xff0c;之前看别人论文进行的参考文献引文标注&#xff0c;感觉特别高级&#xff0c;这项技能早晚…

WORD 常用操作技巧

word2010首页、目录、正文页码设置方法 2013-07-18 12:11:05| 分类&#xff1a; 实用技巧|举报|字号 订阅 引文来源&#xff1a;http://www.hangxyz.com/display-different-page-number-in-word2010.html 欲在线预览或下载完整教程请访问SkyDrive页面 在用Word编辑说明书、计…

利用Word实现交叉引用或引用尾注添加参考文献图解

from&#xff1a;http://www.office68.com/word/word-reference-add.html 1 利用“交叉引用”加参考文献 1 输入参考文献&#xff0c;如下图 2 选中所有文献&#xff0c;为所选文献统一编号&#xff0c;如下图 3 在正文中需要添加参考文献处添加交叉引用&#xff0c;如下图 4相…

标明文献引用及文献列表自动生成(尾注交叉引用)

摘要&#xff1a; 本文介绍利用Word尾注来注明文献引用&#xff0c;并用交叉引用自动生成文献列表&#xff0c;为论文撰写带来极大便利。最后给出参考文献格式。 撰写论文(或者开题报告或者文献综述)需要在文中标明引用&#xff0c;并生成参考文献列表。一种效率低下的方法&…

word2016用尾注引用参考文献

目录 一、添加参考文献尾注 二、为尾注添加方括号 三、去除尾注横线 四、连续参考文献编号&#xff0c;将[1][2][3]变为[1-3] 五、添加方括号后新增参考文献尾注方括号修改方法 六、多个位置引用同一篇参考文献 一、添加参考文献尾注 1.引用-->尾注栏右下角箭头处-->修…

论文参考文献添加---word尾注添加

论文参考文献添加—word尾注添加 坏坏dong小姐 对于广大毕业生童鞋在写毕业论文的时候&#xff0c;最后加参考文献的时候是不是很头疼&#xff1f;格式问题&#xff0c;序号问题。本文通过word2016尾注功能添加参考文献&#xff0c;方便实用。我希望我的实际操作经验能给大家带…

miniUI设置输入框禁止输入和开启

背景&#xff1a; 用 input标签 enabled"false" 属性设置为禁止输入后js怎么也不开开启输入 错误中的尝试&#xff1a; 解决办法 使用miniUI获取对象&#xff0c;并设置属性就好了 解决代码&#xff1a;

java学习笔记(三):前端miniUI控件库入门

java学习笔记(三)&#xff1a;前端miniUI控件库入门 最近在一家公司实习学习&#xff0c;一上来就需要学习了解相关的前端内容——miniUI。而这个内容自己本身并没有了解学习过&#xff0c;上手也是遇到了不少的问题&#xff0c;于是想把自己刚入门的学习经验来分享记录一下。…

【CubeIDE】MiniUI驱动ili9341液晶屏教程

0x00 前言 MiniUI是笔者为一位非常要好的朋友兼师父基于C开发的屏幕驱动框架&#xff0c;MiniUI分为两部分&#xff08;如图&#xff09;&#xff0c;抽象层&#xff08;Abstract layer&#xff09;继承了底层驱动操作LCD的基础API&#xff0c;例如画点&#xff08;DrawPixel&…

Jquery miniUI 开发教程(2) 搭建Jquery miniUI 开发环境

Jquery miniUI 下载地址&#xff1a;http://www.miniui.com/download Note&#xff1a;请根据不同的服务端后台&#xff0c;选择下载不同后台版本的MiniUI。 下载后&#xff0c;解压缩后&#xff0c;如图所示&#xff1a; 各目录文件解释如下&#xff1a; dbsql&#xff1a;示…

mysql 表格控件,jQuery MiniUI 开发教程 表格控件 表格:分页查询(一)

数据表格 参考示例&#xff1a;数据表格 分页表格 一&#xff1a;创建表格 url"../data/DataService.aspx?methodSearchEmployees" idField"id" allowResize"true" > 员工帐号 姓名 性别 薪资 年龄 创建日期 二&#xff1a;数据加载 条件…

MiniUI快速入门教程(二)编写第一个MiniUI程序:Hello, world!

我们开始编写第一个MiniUI程序&#xff0c;代码如下&#xff1a; <!DOCTYPE html /> <html> <head><title> Hello MiniUI!</title><!--jQuery js--><script src"../jquery.js" type"text/javascript"></scri…

MiniUI快速入门教程(五)主框架布局

下面实现一个最典型主框架布局。 效果图如下&#xff1a; 一&#xff1a;创建界面布局 <!--Layout--> <div id"layout1" class"mini-layout" style"width:100%;height:100%;"><div class"header" region"north&qu…

MiniUI快速入门教程(四)表单开发

表单开发包括&#xff1a;布局、验证、加载、提交、清除、重置等。 效果图如下&#xff1a; 表单布局 使用HTML Table标签实现任意丰富的表单布局&#xff1a; <table class"form-table" border"0" cellpadding"1" cellspacing"2"&…

MiniUI 实战演练视频教程-专题视频课程

MiniUI 实战演练视频教程—553人已学习 课程介绍 该视频培训课程主要分享MiniUI文本控件、按钮控件、组合框控件、列表控件、单选、复选框控件、密码、文本块控件、日期选择控件、上传控件、数据网格控件、弹窗、菜单、选项卡、布局等MiniUI的所有知识点。 课程收益 …

MiniUI快速入门教程(一)下载安装

产品下载地址&#xff1a;http://www.miniui.com/download。 Note&#xff1a;请根据不同的服务端后台&#xff0c;选择下载不同后台版本的MiniUI。 下载后&#xff0c;解压缩。 会有如下文件结构&#xff1a; 各目录文件解释如下&#xff1a; dbsql&#xff1a;示例数据库sql文…