当前位置: 首页 > article >正文

Java教程:SE进阶【十万字详解】(中)

在这里插## 标题入图片描述

> 						大家好,我是程序员小羊!

✨博客主页: https://blog.csdn.net/m0_63815035?type=blog

💗《博客内容》:.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识
📢博客专栏: https://blog.csdn.net/m0_63815035/category_11954877.html
📢欢迎点赞 👍 收藏 ⭐留言 📝
📢本文为学习笔记资料,如有侵权,请联系我删除,疏漏之处还请指正🙉
📢大厦之成,非一木之材也;大海之阔,非一流之归也✨

在这里插入图片描述

前言:

欢迎来到小羊的《Java教程:SE进阶》系列的学习之旅!无论你是初学者还是希望深化对Java编程语言理解的开发者,这系列教程都将为你提供系统化的知识和实用的技能,帮助你从零基础起步,逐步掌握Java编程的核心概念和技术。希望大家多多支持小羊吧!!让我们一起开启这段精彩的编程旅程,从零开始Go Go

目录

  • 前言:
  • 一、day08API&异常
    • 1.包装类
      • 1.1 基本类型包装类(记忆)
      • 1.2 Integer类(应用)
      • 1.3 自动拆箱和自动装箱(理解)
      • 1.4 int和String类型的相互转换(记忆)
      • 1.5 字符串数据排序案例(应用)
    • 2.递归
      • 2.1 递归【应用】
      • 2.2 递归求阶乘【应用】
    • 3.数组的高级操作
      • 3.1 二分查找 (理解)
      • 3.2 冒泡排序 (理解)
      • 3.3 Arrays (应用)
    • 4.异常
      • 4.1 异常(记忆)
      • 4.2 编译时异常和运行时异常的区别(记忆)
      • 4.3 JVM默认处理异常的方式(理解)
      • 4.4 查看异常信息 (理解)
      • 4.5 throws方式处理异常(应用)
      • 4.6 throw抛出异常 (应用)
      • 4.7 try-catch方式处理异常(应用)
      • 4.8 Throwable成员方法(应用)
      • 4.9 异常的练习 (应用)
      • 4.10 自定义异常(应用)
  • day09-day010API&&集合
    • 1.时间日期类
      • 1.1 Date类(应用)
      • 1.2 Date类常用方法(应用)
      • 1.3 SimpleDateFormat类(应用)
      • 1.4 时间日期类练习 (应用)
    • 2.Collection集合
      • 2.1数组和集合的区别【理解】
      • 2.2集合类体系结构【理解】
      • 2.3Collection 集合概述和使用【应用】
      • 2.4Collection集合的遍历【应用】
      • 2.5增强for循环【应用】
    • 3.List集合
      • 3.1List集合的概述和特点【记忆】
      • 3.2List集合的特有方法【应用】
    • 4.数据结构
      • 4.1数据结构之栈和队列【记忆】
      • 4.2数据结构之数组和链表【记忆】
    • 5.List集合的实现类
      • 5.1List集合子类的特点【记忆】
      • 5.2LinkedList集合的特有功能【应用】
  • day11集合
    • 1.泛型
      • 1.1泛型概述
    • 2.Set集合
      • 2.1Set集合概述和特点【应用】
      • 2.2Set集合的使用【应用】
    • 3.TreeSet集合
      • 3.1TreeSet集合概述和特点【应用】
      • 3.2TreeSet集合基本使用【应用】
      • 3.3自然排序Comparable的使用【应用】
      • 3.4比较器排序Comparator的使用【应用】
      • 3.5两种比较方式总结【理解】
    • 4.数据结构
      • 4.1二叉树【理解】
      • 4.2二叉查找树【理解】
      • 4.3平衡二叉树【理解】
      • 4.3红黑树【理解】
    • 1.HashSet集合
      • 1.1HashSet集合概述和特点【应用】
      • 1.2HashSet集合的基本应用【应用】
      • 1.3哈希值【理解】
      • 1.4哈希表结构【理解】
      • 1.5HashSet集合存储学生对象并遍历【应用】
    • 2.Map集合
      • 2.1Map集合概述和特点【理解】
      • 2.2Map集合的基本功能【应用】
      • 2.3Map集合的获取功能【应用】
      • 2.4Map集合的遍历(方式1)【应用】
      • 2.5Map集合的遍历(方式2)【应用】
    • 3.HashMap集合
      • 3.1HashMap集合概述和特点【理解】
      • 3.2HashMap集合应用案例【应用】
    • 4.TreeMap集合
      • 4.1TreeMap集合概述和特点【理解】
      • 4.2TreeMap集合应用案例【应用】
    • 5.可变参数
    • 6.创建不可变集合

一、day08API&异常

1.包装类

1.1 基本类型包装类(记忆)

  • 基本类型包装类的作用

    将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据

    常用的操作之一:用于基本数据类型与字符串之间的转换

  • 基本类型对应的包装类

    基本数据类型包装类
    byteByte
    shortShort
    intInteger
    longLong
    floatFloat
    doubleDouble
    charCharacter
    booleanBoolean

1.2 Integer类(应用)

  • Integer类概述

    包装一个对象中的原始类型 int 的值

  • Integer类构造方法

    方法名说明
    public Integer(int value)根据 int 值创建 Integer 对象(过时)
    public Integer(String s)根据 String 值创建 Integer 对象(过时)
    public static Integer valueOf(int i)返回表示指定的 int 值的 Integer 实例
    public static Integer valueOf(String s)返回一个保存指定值的 Integer 对象 String
  • 示例代码

    public class IntegerDemo {
        public static void main(String[] args) {
            //public Integer(int value):根据 int 值创建 Integer 对象(过时)
            Integer i1 = new Integer(100);
            System.out.println(i1);
    
            //public Integer(String s):根据 String 值创建 Integer 对象(过时)
            Integer i2 = new Integer("100");
    //        Integer i2 = new Integer("abc"); //NumberFormatException
            System.out.println(i2);
            System.out.println("--------");
    
            //public static Integer valueOf(int i):返回表示指定的 int 值的 Integer 实例
            Integer i3 = Integer.valueOf(100);
            System.out.println(i3);
    
            //public static Integer valueOf(String s):返回一个保存指定值的Integer对象 String
            Integer i4 = Integer.valueOf("100");
            System.out.println(i4);
        }
    }
    

1.3 自动拆箱和自动装箱(理解)

  • 自动装箱

    ​ 把基本数据类型转换为对应的包装类类型

  • 自动拆箱

    ​ 把包装类类型转换为对应的基本数据类型

  • 示例代码

    Integer i = 100;  // 自动装箱
    i += 200;         // i = i + 200;  i + 200 自动拆箱;i = i + 200; 是自动装箱
    

1.4 int和String类型的相互转换(记忆)

  • int转换为String

    • 转换方式

      • 方式一:直接在数字后加一个空字符串
      • 方式二:通过String类静态方法valueOf()
    • 示例代码

      public class IntegerDemo {
          public static void main(String[] args) {
              //int --- String
              int number = 100;
              //方式1
              String s1 = number + "";
              System.out.println(s1);
              //方式2
              //public static String valueOf(int i)
              String s2 = String.valueOf(number);
              System.out.println(s2);
              System.out.println("--------");
          }
      }
      
  • String转换为int

    • 转换方式

      • 方式一:先将字符串数字转成Integer,再调用valueOf()方法
      • 方式二:通过Integer静态方法parseInt()进行转换
    • 示例代码

      public class IntegerDemo {
          public static void main(String[] args) {
              //String --- int
              String s = "100";
              //方式1:String --- Integer --- int
              Integer i = Integer.valueOf(s);
              //public int intValue()
              int x = i.intValue();
              System.out.println(x);
              //方式2
              //public static int parseInt(String s)
              int y = Integer.parseInt(s);
              System.out.println(y);
          }
      }
      

1.5 字符串数据排序案例(应用)

  • 案例需求

    ​ 有一个字符串:“91 27 46 38 50”,请写程序实现最终输出结果是:27 38 46 50 91

  • 代码实现

    public class IntegerTest {
        public static void main(String[] args) {
            //定义一个字符串
            String s = "91 27 46 38 50";
    
            //把字符串中的数字数据存储到一个int类型的数组中
            String[] strArray = s.split(" ");
    //        for(int i=0; i<strArray.length; i++) {
    //            System.out.println(strArray[i]);
    //        }
    
            //定义一个int数组,把 String[] 数组中的每一个元素存储到 int 数组中
            int[] arr = new int[strArray.length];
            for(int i=0; i<arr.length; i++) {
                arr[i] = Integer.parseInt(strArray[i]);
            }
    
            //对 int 数组进行排序
            Arrays.sort(arr);
    
          	for(int i=0; i<arr.length; i++){
             System.out.print(arr[i] + " ");
          	}
    }
    

2.递归

2.1 递归【应用】

  • 递归的介绍

    • 以编程的角度来看,递归指的是方法定义中调用方法本身的现象
    • 把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
    • 递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算
  • 递归的基本使用

    public class MyFactorialDemo2 {
        public static void main(String[] args) {
            int sum = getSum(100);
            System.out.println(sum);
        }
    
        private static int getSum(int i) {
            //1- 100之间的和
                //100 + (1-99之间的和)
                        // 99 + (1- 98之间的和)
                            //....
                                //1
            //方法的作用: 求 1- i 之间和
            if(i == 1){
                return 1;
            }else{
                return i + getSum(i -1);
            }
        }
    }    
    
  • 递归的注意事项

    • 递归一定要有出口。否则内存溢出
    • 递归虽然有出口,但是递归的次数也不宜过多。否则内存溢出

2.2 递归求阶乘【应用】

  • 案例需求

    ​ 用递归求5的阶乘,并把结果在控制台输出

  • 代码实现

    public class DiGuiDemo01 {
        public static void main(String[] args) {
            //调用方法
            int result = jc(5);
            //输出结果
            System.out.println("5的阶乘是:" + result);
        }
    
        //定义一个方法,用于递归求阶乘,参数为一个int类型的变量
        public static int jc(int n) {
            //在方法内部判断该变量的值是否是1
            if(n == 1) {
                //是:返回1
                return 1;
            } else {
                //不是:返回n*(n-1)!
                return n*jc(n-1);
            }
        }
    }
    
  • 内存图

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.数组的高级操作

3.1 二分查找 (理解)

  • 二分查找概述

    查找指定元素在数组中的位置时,以前的方式是通过遍历,逐个获取每个元素,看是否是要查找的元素,这种方式当数组元素较多时,查找的效率很低

    二分查找也叫折半查找,每次可以去掉一半的查找范围,从而提高查找的效率

  • 需求

    在数组{1,2,3,4,5,6,7,8,9,10}中,查找某个元素的位置

  • 实现步骤

    1. 定义两个变量,表示要查找的范围。默认min = 0 ,max = 最大索引
    2. 循环查找,但是min <= max
    3. 计算出mid的值
    4. 判断mid位置的元素是否为要查找的元素,如果是直接返回对应索引
    5. 如果要查找的值在mid的左半边,那么min值不变,max = mid -1.继续下次循环查找
    6. 如果要查找的值在mid的右半边,那么max值不变,min = mid + 1.继续下次循环查找
    7. 当min > max 时,表示要查找的元素在数组中不存在,返回-1.
  • 代码实现

    public class MyBinarySearchDemo {
        public static void main(String[] args) {
            int [] arr = {1,2,3,4,5,6,7,8,9,10};
            int number = 11;
    
            //1,我现在要干嘛? --- 二分查找
            //2.我干这件事情需要什么? --- 数组 元素
            //3,我干完了,要不要把结果返回调用者 --- 把索引返回给调用者
            int index = binarySearchForIndex(arr,number);
            System.out.println(index);
        }
    
        private static int binarySearchForIndex(int[] arr, int number) {
            //1,定义查找的范围
            int min = 0;
            int max = arr.length - 1;
            //2.循环查找 min <= max
            while(min <= max){
                //3.计算出中间位置 mid
                int mid = (min + max) >> 1;
                //mid指向的元素 > number
                if(arr[mid] > number){
                    //表示要查找的元素在左边.
                    max = mid -1;
                }else if(arr[mid] < number){
                    //mid指向的元素 < number
                    //表示要查找的元素在右边.
                    min = mid + 1;
                }else{
                    //mid指向的元素 == number
                    return mid;
                }
            }
            //如果min大于了max就表示元素不存在,返回-1.
            return -1;
        }
      
    }
    
  • 注意事项

    有一个前提条件,数组内的元素一定要按照大小顺序排列,如果没有大小顺序,是不能使用二分查找法的

3.2 冒泡排序 (理解)

  • 冒泡排序概述

    一种排序的方式,对要进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面,依次对所有的数据进行操作,直至所有数据按要求完成排序

    如果有n个数据进行排序,总共需要比较n-1次

    每一次比较完毕,下一次的比较就会少一个数据参与

  • 代码实现

    public class MyBubbleSortDemo2 {
        public static void main(String[] args) {
            int[] arr = {3, 5, 2, 1, 4};
            //1 2 3 4 5
            bubbleSort(arr);
        }
    
        private static void bubbleSort(int[] arr) {
            //外层循环控制的是次数 比数组的长度少一次.
            for (int i = 0; i < arr.length -1; i++) {
                //内存循环就是实际循环比较的
                //-1 是为了让数组不要越界
                //-i 每一轮结束之后,我们就会少比一个数字.
                for (int j = 0; j < arr.length - 1 - i; j++) {
                    if (arr[j] > arr[j + 1]) {
                        int temp = arr[j];
                        arr[j] = arr[j + 1];
                        arr[j + 1] = temp;
                    }
                }
            }
    
            printArr(arr);
        }
    
        private static void printArr(int[] arr) {
            for (int i = 0; i < arr.length; i++) {
                System.out.print(arr[i] + " ");
            }
            System.out.println();
        }
      
    }
    

3.3 Arrays (应用)

  • Arrays的常用方法

    方法名说明
    public static String toString(int[] a)返回指定数组的内容的字符串表示形式
    public static void sort(int[] a)按照数字顺序排列指定的数组
    public static int binarySearch(int[] a, int key)利用二分查找返回指定元素的索引
  • 示例代码

    public class MyArraysDemo {
          public static void main(String[] args) {
      //        public static String toString(int[] a)    返回指定数组的内容的字符串表示形式
      //        int [] arr = {3,2,4,6,7};
      //        System.out.println(Arrays.toString(arr));
    
      //        public static void sort(int[] a)	  按照数字顺序排列指定的数组
      //        int [] arr = {3,2,4,6,7};
      //        Arrays.sort(arr);
      //        System.out.println(Arrays.toString(arr));
    
      //        public static int binarySearch(int[] a, int key) 利用二分查找返回指定元素的索引
              int [] arr = {1,2,3,4,5,6,7,8,9,10};
              int index = Arrays.binarySearch(arr, 0);
              System.out.println(index);
              //1,数组必须有序
              //2.如果要查找的元素存在,那么返回的是这个元素实际的索引
              //3.如果要查找的元素不存在,那么返回的是 (-插入点-1)
                  //插入点:如果这个元素在数组中,他应该在哪个索引上.
          }
      }
    
  • 工具类设计思想

    1. 构造方法用 private 修饰
    2. 成员用 public static 修饰

4.异常

4.1 异常(记忆)

  • 异常的概述

    ​ 异常就是程序出现了不正常的情况

  • 异常的体系结构

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.2 编译时异常和运行时异常的区别(记忆)

  • 编译时异常

    • 都是Exception类及其子类
    • 必须显示处理,否则程序就会发生错误,无法通过编译
  • 运行时异常

    • 都是RuntimeException类及其子类
    • 无需显示处理,也可以和编译时异常一样处理
  • 图示

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.3 JVM默认处理异常的方式(理解)

  • 如果程序出现了问题,我们没有做任何处理,最终JVM 会做默认的处理,处理方式有如下两个步骤:
    • 把异常的名称,错误原因及异常出现的位置等信息输出在了控制台
    • 程序停止执行

4.4 查看异常信息 (理解)

控制台在打印异常信息时,会打印异常类名,异常出现的原因,异常出现的位置

我们调bug时,可以根据提示,找到异常出现的位置,分析原因,修改异常代码

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.5 throws方式处理异常(应用)

  • 定义格式

    public void 方法() throws 异常类名 {
        
    }
    
  • 示例代码

    public class ExceptionDemo {
        public static void main(String[] args) throws ParseException{
            System.out.println("开始");
    //        method();
              method2();
    
            System.out.println("结束");
        }
    
        //编译时异常
        public static void method2() throws ParseException {
            String s = "2048-08-09";
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date d = sdf.parse(s);
            System.out.println(d);
        }
    
        //运行时异常
        public static void method() throws ArrayIndexOutOfBoundsException {
            int[] arr = {1, 2, 3};
            System.out.println(arr[3]);
        }
    }
    
  • 注意事项

    • 这个throws格式是跟在方法的括号后面的
    • 编译时异常必须要进行处理,两种处理方案:try…catch …或者 throws,如果采用 throws 这种方案,在方法上进行显示声明,将来谁调用这个方法谁处理
    • 运行时异常因为在运行时才会发生,所以在方法后面可以不写,运行时出现异常默认交给jvm处理

4.6 throw抛出异常 (应用)

  • 格式

    throw new 异常();

  • 注意

    这个格式是在方法内的,表示当前代码手动抛出一个异常,下面的代码不用再执行了

  • throws和throw的区别

    throwsthrow
    用在方法声明后面,跟的是异常类名用在方法体内,跟的是异常对象名
    表示声明异常,调用该方法有可能会出现这样的异常表示手动抛出异常对象,由方法体内的语句处理
  • 示例代码

    public class ExceptionDemo8 {
        public static void main(String[] args) {
            //int [] arr = {1,2,3,4,5};
            int [] arr = null;
            printArr(arr);//就会 接收到一个异常.
                            //我们还需要自己处理一下异常.
        }
    
        private static void printArr(int[] arr) {
            if(arr == null){
                //调用者知道成功打印了吗?
                //System.out.println("参数不能为null");
                throw new NullPointerException(); //当参数为null的时候
                                                //手动创建了一个异常对象,抛给了调用者,产生了一个异常
            }else{
                for (int i = 0; i < arr.length; i++) {
                    System.out.println(arr[i]);
                }
            }
        }
    
    }
    

4.7 try-catch方式处理异常(应用)

  • 定义格式

    try {
    	可能出现异常的代码;
    } catch(异常类名 变量名) {
    	异常的处理代码;
    }
    
  • 执行流程

    • 程序从 try 里面的代码开始执行
    • 出现异常,就会跳转到对应的 catch 里面去执行
    • 执行完毕之后,程序还可以继续往下执行
  • 示例代码

    public class ExceptionDemo01 {
        public static void main(String[] args) {
            System.out.println("开始");
            method();
            System.out.println("结束");
        }
    
        public static void method() {
            try {
                int[] arr = {1, 2, 3};
                System.out.println(arr[3]);
                System.out.println("这里能够访问到吗");
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("你访问的数组索引不存在,请回去修改为正确的索引");
            }
        }
    }
    
  • 注意

    1. 如果 try 中没有遇到问题,怎么执行?

      会把try中所有的代码全部执行完毕,不会执行catch里面的代码

    2. 如果 try 中遇到了问题,那么 try 下面的代码还会执行吗?

      那么直接跳转到对应的catch语句中,try下面的代码就不会再执行了
      当catch里面的语句全部执行完毕,表示整个体系全部执行完全,继续执行下面的代码

    3. 如果出现的问题没有被捕获,那么程序如何运行?

      那么try…catch就相当于没有写.那么也就是自己没有处理.
      默认交给虚拟机处理.

    4. 同时有可能出现多个异常怎么处理?

      出现多个异常,那么就写多个catch就可以了.
      注意点:如果多个异常之间存在子父类关系.那么父类一定要写在下面

4.8 Throwable成员方法(应用)

  • 常用方法

    方法名说明
    public String getMessage()返回此 throwable 的详细消息字符串
    public String toString()返回此可抛出的简短描述
    public void printStackTrace()把异常的错误信息输出在控制台
  • 示例代码

    public class ExceptionDemo02 {
        public static void main(String[] args) {
            System.out.println("开始");
            method();
            System.out.println("结束");
        }
    
        public static void method() {
            try {
                int[] arr = {1, 2, 3};
                System.out.println(arr[3]); //new ArrayIndexOutOfBoundsException();
                System.out.println("这里能够访问到吗");
            } catch (ArrayIndexOutOfBoundsException e) { //new ArrayIndexOutOfBoundsException();
    //            e.printStackTrace();
    
                //public String getMessage():返回此 throwable 的详细消息字符串
    //            System.out.println(e.getMessage());
                //Index 3 out of bounds for length 3
    
                //public String toString():返回此可抛出的简短描述
    //            System.out.println(e.toString());
                //java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
    
                //public void printStackTrace():把异常的错误信息输出在控制台
                e.printStackTrace();
    //            java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
    //            at com.itheima_02.ExceptionDemo02.method(ExceptionDemo02.java:18)
    //            at com.itheima_02.ExceptionDemo02.main(ExceptionDemo02.java:11)
    
            }
        }
    }
    

4.9 异常的练习 (应用)

  • 需求

    键盘录入学生的姓名和年龄,其中年龄为18 - 25岁,超出这个范围是异常数据不能赋值.需要重新录入,一直录到正确为止

  • 实现步骤

    1. 创建学生对象
    2. 键盘录入姓名和年龄,并赋值给学生对象
    3. 如果是非法数据就再次录入
  • 代码实现

    学生类

    public class Student {
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            if(age >= 18 && age <= 25){
                this.age = age;
            }else{
                //当年龄不合法时,产生一个异常
                throw new RuntimeException("年龄超出了范围");
            }
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    

    测试类

    public class ExceptionDemo12 {
        public static void main(String[] args) {
            // 键盘录入学生的姓名和年龄,其中年龄为 18 - 25岁,
            // 超出这个范围是异常数据不能赋值.需要重新录入,一直录到正确为止。
    
            Student s = new Student();
    
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入姓名");
            String name = sc.nextLine();
            s.setName(name);
           while(true){
               System.out.println("请输入年龄");
               String ageStr = sc.nextLine();
               try {
                   int age = Integer.parseInt(ageStr);
                   s.setAge(age);
                   break;
               } catch (NumberFormatException e) {
                   System.out.println("请输入一个整数");
                   continue;
               } catch (AgeOutOfBoundsException e) {
                   System.out.println(e.toString());
                   System.out.println("请输入一个符合范围的年龄");
                   continue;
               }
               /*if(age >= 18 && age <=25){
                   s.setAge(age);
                   break;
               }else{
                   System.out.println("请输入符合要求的年龄");
                   continue;
               }*/
           }
            System.out.println(s);
    
        }
    }
    

4.10 自定义异常(应用)

  • 自定义异常概述

    当Java中提供的异常不能满足我们的需求时,我们可以自定义异常

  • 实现步骤

    1. 定义异常类
    2. 写继承关系
    3. 提供空参构造
    4. 提供带参构造
  • 代码实现

    异常类

    public class AgeOutOfBoundsException extends RuntimeException {
        public AgeOutOfBoundsException() {
        }
    
        public AgeOutOfBoundsException(String message) {
            super(message);
        }
    }
    

    学生类

    public class Student {
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            if(age >= 18 && age <= 25){
                this.age = age;
            }else{
                //如果Java中提供的异常不能满足我们的需求,我们可以使用自定义的异常
                throw new AgeOutOfBoundsException("年龄超出了范围");
            }
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    

    测试类

    public class ExceptionDemo12 {
        public static void main(String[] args) {
            // 键盘录入学生的姓名和年龄,其中年龄为 18 - 25岁,
            // 超出这个范围是异常数据不能赋值.需要重新录入,一直录到正确为止。
    
            Student s = new Student();
    
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入姓名");
            String name = sc.nextLine();
            s.setName(name);
           while(true){
               System.out.println("请输入年龄");
               String ageStr = sc.nextLine();
               try {
                   int age = Integer.parseInt(ageStr);
                   s.setAge(age);
                   break;
               } catch (NumberFormatException e) {
                   System.out.println("请输入一个整数");
                   continue;
               } catch (AgeOutOfBoundsException e) {
                   System.out.println(e.toString());
                   System.out.println("请输入一个符合范围的年龄");
                   continue;
               }
               /*if(age >= 18 && age <=25){
                   s.setAge(age);
                   break;
               }else{
                   System.out.println("请输入符合要求的年龄");
                   continue;
               }*/
           }
            System.out.println(s);
    
        }
    }
    

day09-day010API&&集合

1.时间日期类

1.1 Date类(应用)

  • 计算机中时间原点

    1970年1月1日 00:00:00

  • 时间换算单位

    1秒 = 1000毫秒

  • Date类概述

    Date 代表了一个特定的时间,精确到毫秒

  • Date类构造方法

    方法名说明
    public Date()分配一个 Date对象,并初始化,以便它代表它被分配的时间,精确到毫秒
    public Date(long date)分配一个 Date对象,并将其初始化为表示从标准基准时间起指定的毫秒数
  • 示例代码

    public class DateDemo01 {
        public static void main(String[] args) {
            //public Date():分配一个 Date对象,并初始化,以便它代表它被分配的时间,精确到毫秒
            Date d1 = new Date();
            System.out.println(d1);
    
            //public Date(long date):分配一个 Date对象,并将其初始化为表示从标准基准时间起指定的毫秒数
            long date = 1000*60*60;
            Date d2 = new Date(date);
            System.out.println(d2);
        }
    }
    

1.2 Date类常用方法(应用)

  • 常用方法

    方法名说明
    public long getTime()获取的是日期对象从1970年1月1日 00:00:00到现在的毫秒值
    public void setTime(long time)设置时间,给的是毫秒值
  • 示例代码

    public class DateDemo02 {
        public static void main(String[] args) {
            //创建日期对象
            Date d = new Date();
    
            //public long getTime():获取的是日期对象从1970年1月1日 00:00:00到现在的毫秒值
    //        System.out.println(d.getTime());
    //        System.out.println(d.getTime() * 1.0 / 1000 / 60 / 60 / 24 / 365 + "年");
    
            //public void setTime(long time):设置时间,给的是毫秒值
    //        long time = 1000*60*60;
            long time = System.currentTimeMillis();
            d.setTime(time);
    
            System.out.println(d);
        }
    }
    

1.3 SimpleDateFormat类(应用)

  • SimpleDateFormat类概述

    ​ SimpleDateFormat是一个具体的类,用于以区域设置敏感的方式格式化和解析日期。

    ​ 我们重点学习日期格式化和解析

  • SimpleDateFormat类构造方法

    方法名说明
    public SimpleDateFormat()构造一个SimpleDateFormat,使用默认模式和日期格式
    public SimpleDateFormat(String pattern)构造一个SimpleDateFormat使用给定的模式和默认的日期格式
  • SimpleDateFormat类的常用方法

    • 格式化(从Date到String)
      • public final String format(Date date):将日期格式化成日期/时间字符串
    • 解析(从String到Date)
      • public Date parse(String source):从给定字符串的开始解析文本以生成日期
  • 示例代码

    public class SimpleDateFormatDemo {
        public static void main(String[] args) throws ParseException {
            //格式化:从 Date 到 String
            Date d = new Date();
    //        SimpleDateFormat sdf = new SimpleDateFormat();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            String s = sdf.format(d);
            System.out.println(s);
            System.out.println("--------");
    
            //从 String 到 Date
            String ss = "2048-08-09 11:11:11";
            //ParseException
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date dd = sdf2.parse(ss);
            System.out.println(dd);
        }
    }
    

1.4 时间日期类练习 (应用)

  • 需求

    秒杀开始时间是2020年11月11日 00:00:00,结束时间是2020年11月11日 00:10:00,用户小贾下单时间是2020年11月11日 00:03:47,用户小皮下单时间是2020年11月11日 00:10:11,判断用户有没有成功参与秒杀活动

  • 实现步骤

    1. 判断下单时间是否在开始到结束的范围内
    2. 把字符串形式的时间变成毫秒值
  • 代码实现

    public class DateDemo5 {
        public static void main(String[] args) throws ParseException {
            //开始时间:2020年11月11日 0:0:0
            //结束时间:2020年11月11日 0:10:0
    
            //小贾2020年11月11日 0:03:47
            //小皮2020年11月11日 0:10:11
    
            //1.判断两位同学的下单时间是否在范围之内就可以了。
    
            //2.要把每一个时间都换算成毫秒值。
    
            String start = "2020年11月11日 0:0:0";
            String end = "2020年11月11日 0:10:0";
    
            String jia = "2020年11月11日 0:03:47";
            String pi = "2020年11月11日 0:10:11";
    
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            long startTime = sdf.parse(start).getTime();
            long endTime = sdf.parse(end).getTime();
    
    //        System.out.println(startTime);
    //        System.out.println(endTime);
            long jiaTime = sdf.parse(jia).getTime();
            long piTime = sdf.parse(pi).getTime();
    
            if(jiaTime >= startTime && jiaTime <= endTime){
                System.out.println("小贾同学参加上了秒杀活动");
            }else{
                System.out.println("小贾同学没有参加上秒杀活动");
            }
    
            System.out.println("------------------------");
    
            if(piTime >= startTime && piTime <= endTime){
                System.out.println("小皮同学参加上了秒杀活动");
            }else{
                System.out.println("小皮同学没有参加上秒杀活动");
            }
    
        }
      
    }
    

2.Collection集合

2.1数组和集合的区别【理解】

  • 相同点

    都是容器,可以存储多个数据

  • 不同点

    • 数组的长度是不可变的,集合的长度是可变的

    • 数组可以存基本数据类型和引用数据类型

      集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类

2.2集合类体系结构【理解】

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.3Collection 集合概述和使用【应用】

  • Collection集合概述

    • 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
    • JDK 不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现
  • 创建Collection集合的对象

    • 多态的方式
    • 具体的实现类ArrayList
  • Collection集合常用方法

    方法名说明
    boolean add(E e)添加元素
    boolean remove(Object o)从集合中移除指定的元素
    boolean removeIf(Object o)根据条件进行移除
    void clear()清空集合中的元素
    boolean contains(Object o)判断集合中是否存在指定的元素
    boolean isEmpty()判断集合是否为空
    int size()集合的长度,也就是集合中元素的个数

2.4Collection集合的遍历【应用】

  • 迭代器介绍

    • 迭代器,集合的专用遍历方式
    • Iterator iterator(): 返回此集合中元素的迭代器,通过集合对象的iterator()方法得到
  • Iterator中的常用方法

    ​ boolean hasNext(): 判断当前位置是否有元素可以被取出
    ​ E next(): 获取当前位置的元素,将迭代器对象移向下一个索引位置

  • Collection集合的遍历

    public class IteratorDemo1 {
        public static void main(String[] args) {
            //创建集合对象
            Collection<String> c = new ArrayList<>();
    
            //添加元素
            c.add("hello");
            c.add("world");
            c.add("java");
            c.add("javaee");
    
            //Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
            Iterator<String> it = c.iterator();
    
            //用while循环改进元素的判断和获取
            while (it.hasNext()) {
                String s = it.next();
                System.out.println(s);
            }
        }
    }
    
  • 迭代器中删除的方法

    ​ void remove(): 删除迭代器对象当前指向的元素

    public class IteratorDemo2 {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<>();
            list.add("a");
            list.add("b");
            list.add("b");
            list.add("c");
            list.add("d");
    
            Iterator<String> it = list.iterator();
            while(it.hasNext()){
                String s = it.next();
                if("b".equals(s)){
                    //指向谁,那么此时就删除谁.
                    it.remove();
                }
            }
            System.out.println(list);
        }
    }
    

2.5增强for循环【应用】

  • 介绍

    • 它是JDK5之后出现的,其内部原理是一个Iterator迭代器
    • 实现Iterable接口的类才可以使用迭代器和增强for
    • 简化数组和Collection集合的遍历
  • 格式

    ​ for(集合/数组中元素的数据类型 变量名 : 集合/数组名) {

    ​ // 已经将当前遍历到的元素封装到变量中了,直接使用变量即可

    ​ }

  • 代码

    public class MyCollectonDemo1 {
        public static void main(String[] args) {
            ArrayList<String> list =  new ArrayList<>();
            list.add("a");
            list.add("b");
            list.add("c");
            list.add("d");
            list.add("e");
            list.add("f");
    
            //1,数据类型一定是集合或者数组中元素的类型
            //2,str仅仅是一个变量名而已,在循环的过程中,依次表示集合或者数组中的每一个元素
            //3,list就是要遍历的集合或者数组
            for(String str : list){
                System.out.println(str);
            }
        }
    }
    

3.List集合

3.1List集合的概述和特点【记忆】

  • List集合的概述
    • 有序集合,这里的有序指的是存取顺序
    • 用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素
    • 与Set集合不同,列表通常允许重复的元素
  • List集合的特点
    • 存取有序
    • 可以重复
    • 有索引

3.2List集合的特有方法【应用】

  • 方法介绍

    方法名描述
    void add(int index,E element)在此集合中的指定位置插入指定的元素
    E remove(int index)删除指定索引处的元素,返回被删除的元素
    E set(int index,E element)修改指定索引处的元素,返回被修改的元素
    E get(int index)返回指定索引处的元素
  • 示例代码

    public class MyListDemo {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
            //method1(list);
            //method2(list);
            //method3(list);
            //method4(list);
        }
    
        private static void method4(List<String> list) {
            //        E get(int index)		返回指定索引处的元素
            String s = list.get(0);
            System.out.println(s);
        }
    
        private static void method3(List<String> list) {
            //        E set(int index,E element)	修改指定索引处的元素,返回被修改的元素
            //被替换的那个元素,在集合中就不存在了.
            String result = list.set(0, "qqq");
            System.out.println(result);
            System.out.println(list);
        }
    
        private static void method2(List<String> list) {
            //        E remove(int index)		删除指定索引处的元素,返回被删除的元素
            //在List集合中有两个删除的方法
            //第一个 删除指定的元素,返回值表示当前元素是否删除成功
            //第二个 删除指定索引的元素,返回值表示实际删除的元素
            String s = list.remove(0);
            System.out.println(s);
            System.out.println(list);
        }
    
        private static void method1(List<String> list) {
            //        void add(int index,E element)	在此集合中的指定位置插入指定的元素
            //原来位置上的元素往后挪一个索引.
            list.add(0,"qqq");
            System.out.println(list);
        }
    }
    

4.数据结构

4.1数据结构之栈和队列【记忆】

  • 栈结构

    ​ 先进后出

  • 队列结构

    ​ 先进先出

4.2数据结构之数组和链表【记忆】

  • 数组结构

    ​ 查询快、增删慢

  • 队列结构

    ​ 查询慢、增删快

5.List集合的实现类

5.1List集合子类的特点【记忆】

  • ArrayList集合

    ​ 底层是数组结构实现,查询快、增删慢

  • LinkedList集合

    ​ 底层是链表结构实现,查询慢、增删快

5.2LinkedList集合的特有功能【应用】

  • 特有方法

    方法名说明
    public void addFirst(E e)在该列表开头插入指定的元素
    public void addLast(E e)将指定的元素追加到此列表的末尾
    public E getFirst()返回此列表中的第一个元素
    public E getLast()返回此列表中的最后一个元素
    public E removeFirst()从此列表中删除并返回第一个元素
    public E removeLast()从此列表中删除并返回最后一个元素
  • 示例代码

    public class MyLinkedListDemo4 {
        public static void main(String[] args) {
            LinkedList<String> list = new LinkedList<>();
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
    //        public void addFirst(E e)	在该列表开头插入指定的元素
            //method1(list);
    
    //        public void addLast(E e)	将指定的元素追加到此列表的末尾
            //method2(list);
    
    //        public E getFirst()		返回此列表中的第一个元素
    //        public E getLast()		返回此列表中的最后一个元素
            //method3(list);
    
    //        public E removeFirst()		从此列表中删除并返回第一个元素
    //        public E removeLast()		从此列表中删除并返回最后一个元素
            //method4(list);
          
        }
    
        private static void method4(LinkedList<String> list) {
            String first = list.removeFirst();
            System.out.println(first);
    
            String last = list.removeLast();
            System.out.println(last);
    
            System.out.println(list);
        }
    
        private static void method3(LinkedList<String> list) {
            String first = list.getFirst();
            String last = list.getLast();
            System.out.println(first);
            System.out.println(last);
        }
    
        private static void method2(LinkedList<String> list) {
            list.addLast("www");
            System.out.println(list);
        }
    
        private static void method1(LinkedList<String> list) {
            list.addFirst("qqq");
            System.out.println(list);
        }
    }
    

day11集合

1.泛型

1.1泛型概述

  • 泛型的介绍

    ​ 泛型是JDK5中引入的特性,它提供了编译时类型安全检测机制

  • 泛型的好处

    1. 把运行时期的问题提前到了编译期间
    2. 避免了强制类型转换
  • 泛型的定义格式

    • <类型>: 指定一种类型的格式.尖括号里面可以任意书写,一般只写一个字母.例如:
    • <类型1,类型2…>: 指定多种类型的格式,多种类型之间用逗号隔开.例如: <E,T> <K,V>

2.Set集合

2.1Set集合概述和特点【应用】

  • 不可以存储重复元素
  • 没有索引,不能使用普通for循环遍历

2.2Set集合的使用【应用】

存储字符串并遍历

public class MySet1 {
    public static void main(String[] args) {
      	//创建集合对象
        Set<String> set = new TreeSet<>();
      	//添加元素
        set.add("ccc");
        set.add("aaa");
        set.add("aaa");
        set.add("bbb");

//        for (int i = 0; i < set.size(); i++) {
//            //Set集合是没有索引的,所以不能使用通过索引获取元素的方法
//        }
      
      	//遍历集合
        Iterator<String> it = set.iterator();
        while (it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("-----------------------------------");
        for (String s : set) {
            System.out.println(s);
        }
    }
}

3.TreeSet集合

3.1TreeSet集合概述和特点【应用】

  • 不可以存储重复元素
  • 没有索引
  • 可以将元素按照规则进行排序
    • TreeSet():根据其元素的自然排序进行排序
    • TreeSet(Comparator comparator) :根据指定的比较器进行排序

3.2TreeSet集合基本使用【应用】

存储Integer类型的整数并遍历

public class TreeSetDemo01 {
    public static void main(String[] args) {
        //创建集合对象
        TreeSet<Integer> ts = new TreeSet<Integer>();

        //添加元素
        ts.add(10);
        ts.add(40);
        ts.add(30);
        ts.add(50);
        ts.add(20);

        ts.add(30);

        //遍历集合
        for(Integer i : ts) {
            System.out.println(i);
        }
    }
}

3.3自然排序Comparable的使用【应用】

  • 案例需求

    • 存储学生对象并遍历,创建TreeSet集合使用无参构造方法
    • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
  • 实现步骤

    1. 使用空参构造创建TreeSet集合
      • 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
    2. 自定义的Student类实现Comparable接口
      • 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
    3. 重写接口中的compareTo方法
      • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
  • 代码实现

    学生类

    public class Student implements Comparable<Student>{
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        @Override
        public int compareTo(Student o) {
            //按照对象的年龄进行排序
            //主要判断条件: 按照年龄从小到大排序
            int result = this.age - o.age;
            //次要判断条件: 年龄相同时,按照姓名的字母顺序排序
            result = result == 0 ? this.name.compareTo(o.getName()) : result;
            return result;
        }
    }
    

    测试类

    public class MyTreeSet2 {
        public static void main(String[] args) {
            //创建集合对象
            TreeSet<Student> ts = new TreeSet<>();
    	    //创建学生对象
            Student s1 = new Student("zhangsan",28);
            Student s2 = new Student("lisi",27);
            Student s3 = new Student("wangwu",29);
            Student s4 = new Student("zhaoliu",28);
            Student s5 = new Student("qianqi",30);
    		//把学生添加到集合
            ts.add(s1);
            ts.add(s2);
            ts.add(s3);
            ts.add(s4);
            ts.add(s5);
    		//遍历集合
            for (Student student : ts) {
                System.out.println(student);
            }
        }
    }
    

3.4比较器排序Comparator的使用【应用】

  • 案例需求

    • 存储老师对象并遍历,创建TreeSet集合使用带参构造方法
    • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
  • 实现步骤

    • 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
    • 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法
    • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
  • 代码实现

    老师类

    public class Teacher {
        private String name;
        private int age;
    
        public Teacher() {
        }
    
        public Teacher(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Teacher{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    

    测试类

    public class MyTreeSet4 {
        public static void main(String[] args) {
          	//创建集合对象
            TreeSet<Teacher> ts = new TreeSet<>(new Comparator<Teacher>() {
                @Override
                public int compare(Teacher o1, Teacher o2) {
                    //o1表示现在要存入的那个元素
                    //o2表示已经存入到集合中的元素
                  
                    //主要条件
                    int result = o1.getAge() - o2.getAge();
                    //次要条件
                    result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
                    return result;
                }
            });
    		//创建老师对象
            Teacher t1 = new Teacher("zhangsan",23);
            Teacher t2 = new Teacher("lisi",22);
            Teacher t3 = new Teacher("wangwu",24);
            Teacher t4 = new Teacher("zhaoliu",24);
    		//把老师添加到集合
            ts.add(t1);
            ts.add(t2);
            ts.add(t3);
            ts.add(t4);
    		//遍历集合
            for (Teacher teacher : ts) {
                System.out.println(teacher);
            }
        }
    }
    

3.5两种比较方式总结【理解】

  • 两种比较方式小结
    • 自然排序: 自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序
    • 比较器排序: 创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序
    • 在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,必须使用比较器排序
  • 两种方式中关于返回值的规则
    • 如果返回值为负数,表示当前存入的元素是较小值,存左边
    • 如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
    • 如果返回值为正数,表示当前存入的元素是较大值,存右边

4.数据结构

4.1二叉树【理解】

  • 二叉树的特点

    • 二叉树中,任意一个节点的度要小于等于2
      • 节点: 在树结构中,每一个元素称之为节点
      • 度: 每一个节点的子节点数量称之为度
  • 二叉树结构图

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.2二叉查找树【理解】

  • 二叉查找树的特点

    • 二叉查找树,又称二叉排序树或者二叉搜索树
    • 每一个节点上最多有两个子节点
    • 左子树上所有节点的值都小于根节点的值
    • 右子树上所有节点的值都大于根节点的值
  • 二叉查找树结构图

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 二叉查找树和二叉树对比结构图

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 二叉查找树添加节点规则

    • 小的存左边
    • 大的存右边
    • 一样的不存

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.3平衡二叉树【理解】

  • 平衡二叉树的特点

    • 二叉树左右两个子树的高度差不超过1
    • 任意节点的左右两个子树都是一颗平衡二叉树
  • 平衡二叉树旋转

    • 旋转触发时机

      • 当添加一个节点之后,该树不再是一颗平衡二叉树
    • 左旋

      • 就是将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点

      外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

      外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • 右旋

      • 就是将根节点的左侧往右拉,左子节点变成了新的父节点,并把多余的右子节点出让,给已经降级根节点当左子节点

        外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

        外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 平衡二叉树和二叉查找树对比结构图

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 平衡二叉树旋转的四种情况

    • 左左

      • 左左: 当根节点左子树的左子树有节点插入,导致二叉树不平衡

      • 如何旋转: 直接对整体进行右旋即可

        外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • 左右

      • 左右: 当根节点左子树的右子树有节点插入,导致二叉树不平衡

      • 如何旋转: 先在左子树对应的节点位置进行左旋,在对整体进行右旋

        外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • 右右

      • 右右: 当根节点右子树的右子树有节点插入,导致二叉树不平衡

      • 如何旋转: 直接对整体进行左旋即可

        外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • 右左

      • 右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡

      • 如何旋转: 先在右子树对应的节点位置进行右旋,在对整体进行左旋

        外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.3红黑树【理解】

  • 红黑树的特点

    • 平衡二叉B树
    • 每一个节点可以是红或者黑
    • 红黑树不是高度平衡的,它的平衡是通过"自己的红黑规则"进行实现的
  • 红黑树的红黑规则有哪些

    1. 每一个节点或是红色的,或者是黑色的

    2. 根节点必须是黑色

    3. 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的

    4. 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连 的情况)

    5. 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点

      外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 红黑树添加节点的默认颜色

    • 添加节点时,默认为红色,效率高

      外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 红黑树添加节点后如何保持红黑规则

    • 根节点位置
      • 直接变为黑色
    • 非根节点位置
      • 父节点为黑色
        • 不需要任何操作,默认红色即可
      • 父节点为红色
        • 叔叔节点为红色
          1. 将"父节点"设为黑色,将"叔叔节点"设为黑色
          2. 将"祖父节点"设为红色
          3. 如果"祖父节点"为根节点,则将根节点再次变成黑色
        • 叔叔节点为黑色
          1. 将"父节点"设为黑色
          2. 将"祖父节点"设为红色
          3. 以"祖父节点"为支点进行旋转

1.HashSet集合

1.1HashSet集合概述和特点【应用】

  • 底层数据结构是哈希表
  • 存取无序
  • 不可以存储重复元素
  • 没有索引,不能使用普通for循环遍历

1.2HashSet集合的基本应用【应用】

存储字符串并遍历

public class HashSetDemo {
    public static void main(String[] args) {
        //创建集合对象
        HashSet<String> set = new HashSet<String>();

        //添加元素
        set.add("hello");
        set.add("world");
        set.add("java");
        //不包含重复元素的集合
        set.add("world");

        //遍历
        for(String s : set) {
            System.out.println(s);
        }
    }
}

1.3哈希值【理解】

  • 哈希值简介

    ​ 是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值

  • 如何获取哈希值

    ​ Object类中的public int hashCode():返回对象的哈希码值

  • 哈希值的特点

    • 同一个对象多次调用hashCode()方法返回的哈希值是相同的
    • 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同

1.4哈希表结构【理解】

  • JDK1.8以前

    ​ 数组 + 链表

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • JDK1.8以后

    • 节点个数少于等于8个

      ​ 数组 + 链表

    • 节点个数多于8个

      ​ 数组 + 红黑树

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.5HashSet集合存储学生对象并遍历【应用】

  • 案例需求

    • 创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合
    • 要求:学生对象的成员变量值相同,我们就认为是同一个对象
  • 代码实现

    学生类

    public class Student {
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            Student student = (Student) o;
    
            if (age != student.age) return false;
            return name != null ? name.equals(student.name) : student.name == null;
        }
    
        @Override
        public int hashCode() {
            int result = name != null ? name.hashCode() : 0;
            result = 31 * result + age;
            return result;
        }
    }
    

    测试类

    public class HashSetDemo02 {
        public static void main(String[] args) {
            //创建HashSet集合对象
            HashSet<Student> hs = new HashSet<Student>();
    
            //创建学生对象
            Student s1 = new Student("林青霞", 30);
            Student s2 = new Student("张曼玉", 35);
            Student s3 = new Student("王祖贤", 33);
    
            Student s4 = new Student("王祖贤", 33);
    
            //把学生添加到集合
            hs.add(s1);
            hs.add(s2);
            hs.add(s3);
            hs.add(s4);
    
            //遍历集合(增强for)
            for (Student s : hs) {
                System.out.println(s.getName() + "," + s.getAge());
            }
        }
    }
    
  • 总结

    ​ HashSet集合存储自定义类型元素,要想实现元素的唯一,要求必须重写hashCode方法和equals方法

2.Map集合

2.1Map集合概述和特点【理解】

  • Map集合概述

    interface Map<K,V>  K:键的类型;V:值的类型
    
  • Map集合的特点

    • 双列集合,一个键对应一个值
    • 键不可以重复,值可以重复
  • Map集合的基本使用

    public class MapDemo01 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String,String> map = new HashMap<String,String>();
    
            //V put(K key, V value) 将指定的值与该映射中的指定键相关联
            map.put("itheima001","林青霞");
            map.put("itheima002","张曼玉");
            map.put("itheima003","王祖贤");
            map.put("itheima003","柳岩");
    
            //输出集合对象
            System.out.println(map);
        }
    }
    

2.2Map集合的基本功能【应用】

  • 方法介绍

    方法名说明
    V put(K key,V value)添加元素
    V remove(Object key)根据键删除键值对元素
    void clear()移除所有的键值对元素
    boolean containsKey(Object key)判断集合是否包含指定的键
    boolean containsValue(Object value)判断集合是否包含指定的值
    boolean isEmpty()判断集合是否为空
    int size()集合的长度,也就是集合中键值对的个数
  • 示例代码

    public class MapDemo02 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String,String> map = new HashMap<String,String>();
    
            //V put(K key,V value):添加元素
            map.put("张无忌","赵敏");
            map.put("郭靖","黄蓉");
            map.put("杨过","小龙女");
    
            //V remove(Object key):根据键删除键值对元素
    //        System.out.println(map.remove("郭靖"));
    //        System.out.println(map.remove("郭襄"));
    
            //void clear():移除所有的键值对元素
    //        map.clear();
    
            //boolean containsKey(Object key):判断集合是否包含指定的键
    //        System.out.println(map.containsKey("郭靖"));
    //        System.out.println(map.containsKey("郭襄"));
    
            //boolean isEmpty():判断集合是否为空
    //        System.out.println(map.isEmpty());
    
            //int size():集合的长度,也就是集合中键值对的个数
            System.out.println(map.size());
    
            //输出集合对象
            System.out.println(map);
        }
    }
    

2.3Map集合的获取功能【应用】

  • 方法介绍

    方法名说明
    V get(Object key)根据键获取值
    Set keySet()获取所有键的集合
    Collection values()获取所有值的集合
    Set<Map.Entry<K,V>> entrySet()获取所有键值对对象的集合
  • 示例代码

    public class MapDemo03 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String, String> map = new HashMap<String, String>();
    
            //添加元素
            map.put("张无忌", "赵敏");
            map.put("郭靖", "黄蓉");
            map.put("杨过", "小龙女");
    
            //V get(Object key):根据键获取值
    //        System.out.println(map.get("张无忌"));
    //        System.out.println(map.get("张三丰"));
    
            //Set<K> keySet():获取所有键的集合
    //        Set<String> keySet = map.keySet();
    //        for(String key : keySet) {
    //            System.out.println(key);
    //        }
    
            //Collection<V> values():获取所有值的集合
            Collection<String> values = map.values();
            for(String value : values) {
                System.out.println(value);
            }
        }
    }
    

2.4Map集合的遍历(方式1)【应用】

  • 遍历思路

    • 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
      • 把所有的丈夫给集中起来
      • 遍历丈夫的集合,获取到每一个丈夫
      • 根据丈夫去找对应的妻子
  • 步骤分析

    • 获取所有键的集合。用keySet()方法实现
    • 遍历键的集合,获取到每一个键。用增强for实现
    • 根据键去找值。用get(Object key)方法实现
  • 代码实现

    public class MapDemo01 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String, String> map = new HashMap<String, String>();
    
            //添加元素
            map.put("张无忌", "赵敏");
            map.put("郭靖", "黄蓉");
            map.put("杨过", "小龙女");
    
            //获取所有键的集合。用keySet()方法实现
            Set<String> keySet = map.keySet();
            //遍历键的集合,获取到每一个键。用增强for实现
            for (String key : keySet) {
                //根据键去找值。用get(Object key)方法实现
                String value = map.get(key);
                System.out.println(key + "," + value);
            }
        }
    }
    

2.5Map集合的遍历(方式2)【应用】

  • 遍历思路

    • 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
      • 获取所有结婚证的集合
      • 遍历结婚证的集合,得到每一个结婚证
      • 根据结婚证获取丈夫和妻子
  • 步骤分析

    • 获取所有键值对对象的集合
      • Set<Map.Entry<K,V>> entrySet():获取所有键值对对象的集合
    • 遍历键值对对象的集合,得到每一个键值对对象
      • 用增强for实现,得到每一个Map.Entry
    • 根据键值对对象获取键和值
      • 用getKey()得到键
      • 用getValue()得到值
  • 代码实现

    public class MapDemo02 {
        public static void main(String[] args) {
            //创建集合对象
            Map<String, String> map = new HashMap<String, String>();
    
            //添加元素
            map.put("张无忌", "赵敏");
            map.put("郭靖", "黄蓉");
            map.put("杨过", "小龙女");
    
            //获取所有键值对对象的集合
            Set<Map.Entry<String, String>> entrySet = map.entrySet();
            //遍历键值对对象的集合,得到每一个键值对对象
            for (Map.Entry<String, String> me : entrySet) {
                //根据键值对对象获取键和值
                String key = me.getKey();
                String value = me.getValue();
                System.out.println(key + "," + value);
            }
        }
    }
    

3.HashMap集合

3.1HashMap集合概述和特点【理解】

  • HashMap底层是哈希表结构的
  • 依赖hashCode方法和equals方法保证键的唯一
  • 如果键要存储的是自定义对象,需要重写hashCode和equals方法

3.2HashMap集合应用案例【应用】

  • 案例需求

    • 创建一个HashMap集合,键是学生对象(Student),值是居住地 (String)。存储多个元素,并遍历。
    • 要求保证键的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象
  • 代码实现

    学生类

    public class Student {
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            Student student = (Student) o;
    
            if (age != student.age) return false;
            return name != null ? name.equals(student.name) : student.name == null;
        }
    
        @Override
        public int hashCode() {
            int result = name != null ? name.hashCode() : 0;
            result = 31 * result + age;
            return result;
        }
    }
    

    测试类

    public class HashMapDemo {
        public static void main(String[] args) {
            //创建HashMap集合对象
            HashMap<Student, String> hm = new HashMap<Student, String>();
    
            //创建学生对象
            Student s1 = new Student("林青霞", 30);
            Student s2 = new Student("张曼玉", 35);
            Student s3 = new Student("王祖贤", 33);
            Student s4 = new Student("王祖贤", 33);
    
            //把学生添加到集合
            hm.put(s1, "西安");
            hm.put(s2, "武汉");
            hm.put(s3, "郑州");
            hm.put(s4, "北京");
    
            //遍历集合
            Set<Student> keySet = hm.keySet();
            for (Student key : keySet) {
                String value = hm.get(key);
                System.out.println(key.getName() + "," + key.getAge() + "," + value);
            }
        }
    }
    

4.TreeMap集合

4.1TreeMap集合概述和特点【理解】

  • TreeMap底层是红黑树结构
  • 依赖自然排序或者比较器排序,对键进行排序
  • 如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则

4.2TreeMap集合应用案例【应用】

  • 案例需求

    • 创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String),学生属性姓名和年龄,按照年龄进行排序并遍历
    • 要求按照学生的年龄进行排序,如果年龄相同则按照姓名进行排序
  • 代码实现

    学生类

    public class Student implements Comparable<Student>{
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        @Override
        public int compareTo(Student o) {
            //按照年龄进行排序
            int result = o.getAge() - this.getAge();
            //次要条件,按照姓名排序。
            result = result == 0 ? o.getName().compareTo(this.getName()) : result;
            return result;
        }
    }
    

    测试类

    public class Test1 {
        public static void main(String[] args) {
          	// 创建TreeMap集合对象
            TreeMap<Student,String> tm = new TreeMap<>();
          
    		// 创建学生对象
            Student s1 = new Student("xiaohei",23);
            Student s2 = new Student("dapang",22);
            Student s3 = new Student("xiaomei",22);
          
    		// 将学生对象添加到TreeMap集合中
            tm.put(s1,"江苏");
            tm.put(s2,"北京");
            tm.put(s3,"天津");
          
    		// 遍历TreeMap集合,打印每个学生的信息
            tm.forEach(
                    (Student key, String value)->{
                        System.out.println(key + "---" + value);
                    }
            );
        }
    }
    

5.可变参数

  • 可变参数介绍

    • 可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
    • 方法的参数类型已经确定,个数不确定,我们可以使用可变参数
  • 可变参数定义格式

    修饰符 返回值类型 方法名(数据类型… 变量名) {  }
    
  • 可变参数的注意事项

    • 这里的变量其实是一个数组
    • 如果一个方法有多个参数,包含可变参数,可变参数要放在最后
  • 可变参数的基本使用

    public class ArgsDemo01 {
        public static void main(String[] args) {
            System.out.println(sum(10, 20));
            System.out.println(sum(10, 20, 30));
            System.out.println(sum(10, 20, 30, 40));
    
            System.out.println(sum(10,20,30,40,50));
            System.out.println(sum(10,20,30,40,50,60));
            System.out.println(sum(10,20,30,40,50,60,70));
            System.out.println(sum(10,20,30,40,50,60,70,80,90,100));
        }
    
    //    public static int sum(int b,int... a) {
    //        return 0;
    //    }
    
        public static int sum(int... a) {
            int sum = 0;
            for(int i : a) {
                sum += i;
            }
            return sum;
        }
    }
    

6.创建不可变集合

  • 方法介绍

    • 在List、Set、Map接口中,都存在of方法,可以创建一个不可变的集合
      • 这个集合不能添加,不能删除,不能修改
      • 但是可以结合集合的带参构造,实现集合的批量添加
    • 在Map接口中,还有一个ofEntries方法可以提高代码的阅读性
      • 首先会把键值对封装成一个Entry对象,再把这个Entry对象添加到集合当中
  • 示例代码

    public class MyVariableParameter4 {
        public static void main(String[] args) {
            // static <E>  List<E>  of(E…elements)  创建一个具有指定元素的List集合对象
            //static <E>  Set<E>  of(E…elements)    创建一个具有指定元素的Set集合对象
            //static <K , V>   Map<K,V>  of(E…elements) 创建一个具有指定元素的Map集合对象
    
            //method1();
            //method2();
            //method3();
            //method4();
    
        }
    
        private static void method4() {
            Map<String, String> map = Map.ofEntries(
                    Map.entry("zhangsan", "江苏"),
                    Map.entry("lisi", "北京"));
            System.out.println(map);
        }
    
        private static void method3() {
            Map<String, String> map = Map.of("zhangsan", "江苏", "lisi", "北京", "wangwu", "天津");
            System.out.println(map);
        }
    
        private static void method2() {
            //传递的参数当中,不能存在重复的元素。
            Set<String> set = Set.of("a", "b", "c", "d","a");
            System.out.println(set);
        }
    
        private static void method1() {
            List<String> list = List.of("a", "b", "c", "d");
            System.out.println(list);
            //list.add("Q");
            //list.remove("a");
            //list.set(0,"A");
            //System.out.println(list);
    
    //        ArrayList<String> list2 = new ArrayList<>();
    //        list2.add("aaa");
    //        list2.add("aaa");
    //        list2.add("aaa");
    //        list2.add("aaa");
    
            //集合的批量添加。
            //首先是通过调用List.of方法来创建一个不可变的集合,of方法的形参就是一个可变参数。
            //再创建一个ArrayList集合,并把这个不可变的集合中所有的数据,都添加到ArrayList中。
            ArrayList<String> list3 = new ArrayList<>(List.of("a", "b", "c", "d"));
            System.out.println(list3);
        }
    }
    
今天这篇文章就到这里了,大厦之成,非一木之材也;大海之阔,非一流之归也。感谢大家观看本文

在这里插入图片描述


http://www.kler.cn/a/406342.html

相关文章:

  • 了解Redis(第一篇)
  • K8S + Jenkins 做CICD
  • 【2024最新】基于springboot+vue的疫情网课管理系统lw+ppt
  • Docker3:docker基础1
  • el-progress进度条框开着时,要实时刷新显示进度条
  • 机器学习基础05_随机森林线性回归
  • 移动语义和拷贝语义的区别以及智能指针
  • 数据结构--并查集
  • 比rsync更强大的文件同步工具rclone
  • 解析粗糙度仪在工业制造及材料科学和建筑工程领域的重要性
  • 半导体工艺与制造篇5 光刻
  • 40分钟学 Go 语言高并发:并发下载器开发实战教程
  • 「Chromeg谷歌浏览器/Edge浏览器」篡改猴Tempermongkey插件的安装与使用
  • 倒计时功能分享
  • 数据结构-8.Java. 七大排序算法(上篇)
  • Linux 手动升级软件保姆级教程,适用所有软件,不限于麒麟等国产系统
  • 【Golang】协程
  • 迁移学习理论与应用
  • 力扣--LRC 142.训练计划IV
  • Ubuntu ESP32开发环境搭建
  • 五天SpringCloud计划——DAY2之使用Docker完成项目的部署
  • Excel的图表使用和导出准备
  • [面试]-golang基础面试题总结
  • redis7.x源码分析:(4) ae事件处理器(一)
  • 《Django 5 By Example》阅读笔记:p645-p650
  • SQL注入:理解、防范与最佳实践