JAVA基础【第二篇】

news2024/10/17 9:57:31

文章目录

  • 类变量
      • 介绍
      • 语法
      • 代码示例
  • 类方法
      • 介绍
      • 注意事项
      • 代码示例
  • 代码块
      • 介绍
      • 基本语法
      • 注意事项
  • 设计模式
      • 单例设计模式
        • 介绍
        • 饿汉式
        • 懒汉式
        • 两者区别
      • 模板设计模式
        • 介绍
        • 代码示例
  • final关键字
      • 介绍
      • 代码示例
      • 注意事项
  • 抽象类
      • 介绍
      • 注意事项
  • 接口
      • 介绍
      • 基本语法
      • 注意细节
      • 接口特性
  • 内部类
      • 介绍
      • 分类
      • 局部内部类
          • 使用
          • 代码示例
      • 匿名内部类
          • 介绍
          • 基本语法
          • 代码示例
          • 使用细节
      • 成员内部类
          • 说明
          • 代码示例
      • 静态内部类
          • 使用细节
          • 代码示例
  • 自定义枚举类
      • 介绍
      • 使用
  • enum枚举类
      • 注意事项
      • enum常用方法
  • 注解
      • 介绍
      • Annotation介绍
          • **Override代码示例**
          • Deprecated代码示例
          • SuppressWarnings代码示例
  • 异常
      • 概念
      • 异常体系图
      • 异常处理
          • 介绍
          • 方式
          • try-catch-finally使用细节
          • throws使用细节
      • 自定义异常
          • 概念
          • 步骤
          • 代码示例
  • 包装类
      • 介绍
      • 代码示例
      • 包装类的常用方法
          • integer和string类型相互转换
          • 常用方法
          • integer类
          • 大数处理方案
      • String类
          • 介绍
          • 代码示例
          • 创建对象方式
          • 常见方法
          • 代码示例
      • StringBuffer类
          • 介绍
          • 与string类的区别
          • string与stringbuffer的转换
          • 常用方法
      • ​StringBuilder类
          • 介绍
          • 常用方法
          • string,stringbuffer,stringbuilder三者的区别和原则
  • Math类
      • 介绍
      • 常用方法
      • 代码示例
  • Arrays类
      • 常用方法
      • 代码示例
  • System类
          • 常用方法
          • 代码示例
  • 日期类
      • 第一代日期类--Date
          • 介绍
          • 代码示例
      • 第二代日期类--Calendar
          • 介绍
          • 代码示例
      • 第三代日期类
          • 基本使用
          • instant时间戳
  • 集合
      • 介绍
      • 框架体系图
      • Collection的常用接口和方法
          • Collection的接口的特点
          • 常用方法
            • 代码示例
          • 接口遍历元素方式1--使用Iterator(迭代器)
            • 介绍
            • 代码示例
          • 接口遍历元素方式2--for循环增强
            • 介绍
            • 特点
            • 基本语法
            • 代码示例
      • List接口和常用方法
          • 介绍
          • 常用方法
          • 三种遍历方式[ArrayList,LinkedList,Vector]
            • 代码示例
          • 代码示例
      • 各节点的底层架构和原理跳过(516)
  • 泛型
      • 介绍
      • 代码示例
      • 语法
          • 声明
          • 实例化
      • 代码示例
      • 使用细节
          • 代码示例
      • 代码示例*
  • 自定义泛型
    • 自定义泛型类
      • 语法
      • 注意细节
      • 代码示例
    • 自定义泛型接口
      • 基本语法
      • 注意细节
      • 代码示例
    • 自定义泛型方法
      • 基本语法
      • 使用细节
      • 代码示例
    • 泛型通配符
      • 介绍
      • 代码示例

类变量

  1. 介绍

    1. 类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。这个从前面的图也可看出来。
  2. 语法

    1. 访问修饰符 static 数据类型 变量名;
    2. static 访问修饰符 数据类型 变量名;
  3. 代码示例

    1.  package com.hspedu.static_;
      
       public class ChildGame {
      
           public static void main(String[] args) {
      
               //定义一个变量 count, 统计有多少小孩加入了游戏
               int count = 0;
      
               Child child1 = new Child("白骨精");
               child1.join();
               //count++;
               child1.count++;
      
               Child child2 = new Child("狐狸精");
               child2.join();
               //count++;
               child2.count++;
      
               Child child3 = new Child("老鼠精");
               child3.join();
               //count++;
               child3.count++;
      
               //===========
               //类变量,可以通过类名来访问
               System.out.println("共有" + Child.count  + " 小孩加入了游戏...");
               //下面的代码输出什么?
               System.out.println("child1.count=" + child1.count);//3
               System.out.println("child2.count=" + child2.count);//3
               System.out.println("child3.count=" + child3.count);//3
      
      
      
           }
       }
      
       class Child { //类
           private String name;
           //定义一个变量 count ,是一个类变量(静态变量) static 静态
           //该变量最大的特点就是会被Child 类的所有的对象实例共享
           public static int count = 0;
           public Child(String name) {
               this.name = name;
           }
           public void join() {
               System.out.println(name + " 加入了游戏..");
           }
       }
      
       输出结果:
       白骨精 加入了游戏..
       狐狸精 加入了游戏..
       老鼠精 加入了游戏..
       共有3 小孩加入了游戏...
       child1.count=3
       child2.count=3
       child3.count=3
      

类方法

  1. 介绍

    1. 当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率。
  2. 注意事项

    1. 类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区:类方法中无this的参数
      普通方法中隐含着this的参数
    2. 类方法可以通过类名调用,也可以通过对象名调用。
    3. 普通方法和对象有关,需要通过对象名调用,比如对象名.方法名(参数),不能通过类名调用。
    4. 类方法中不允许使用和对象有关的关键字,比如this和super。普通方法(成员方法)可以。
    5. 类方法(静态方法)中只能访问静态变量或静态方法。
    6. 普通成员方法,既可以访问非静态成员,也可以访问静态成员。
    7. 总结:静态方法,只能访问静态的成员,非静态的方法,可以访问静态成员和非静态成员
  3. 代码示例

    1.  package com.hspedu.static_;
      
       public class StaticMethodDetail {
           public static void main(String[] args) {
      
               D.hi();//ok
               //非静态方法,不能通过类名调用
               //D.say();, 错误,需要先创建对象,再调用
               new D().say();//可以
           }
       }
       class D {
      
           private int n1 = 100;
           private static  int n2 = 200;
           public void say() {//非静态方法,普通方法
      
           }
      
           public static  void hi() {//静态方法,类方法
               //类方法中不允许使用和对象有关的关键字,
               //比如this和super。普通方法(成员方法)可以。
               //System.out.println(this.n1);
           }
      
           //类方法(静态方法)中 只能访问 静态变量 或静态方法
           //口诀:静态方法只能访问静态成员.
           public static void hello() {
               System.out.println(n2);
               System.out.println(D.n2);
               //System.out.println(this.n2);不能使用
               hi();//OK
               //say();//错误
           }
           //普通成员方法,既可以访问  非静态成员,也可以访问静态成员
           //小结: 非静态方法可以访问 静态成员和非静态成员
           public void ok() {
               //非静态成员
               System.out.println(n1);
               say();
               //静态成员
               System.out.println(n2);
               hello();
      
           }
       }
       //成功编译
      

代码块

  1. 介绍

    1. 代码化块又称为初始化块,属于类中的成员[即是类的一部分],类似于方法,将逻辑语句封装在方法体中,通过{}包围起来。
      但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。
  2. 基本语法

    1. [修饰符]{
      代码
      };
  3. 注意事项

    1. static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象,就执行。

    2. 类什么时候被加载[重要背!]

      1. ①创建对象实例时(new)
      2. ②创建子类对象实例,父类也会被加载
      3. ③使用类的静态成员时(静态属性,静态方法)案例演示:A类extends B类的静态块
    3. 普通的代码块,在创建对象实例时,会被隐式的调用。被创建一次,就会调用一次。
      如果只是使用类的静态成员时,普通代码块并不会执行。

    4. 小结:

      1. static代码块是类加载时,执行,只会执行一次
      2. 普通代码块是在创建对象时调用的,创建一次,调用一次
      3. 类加载的3种情况,需要记住.
    5. 代码示例

      1.  package com.hspedu.codeblock_;
        
         public class CodeBlockDetail01 {
             public static void main(String[] args) {
        
                 //类被加载的情况举例
                 //1. 创建对象实例时(new)
                 // AA aa = new AA();
                 //2. 创建子类对象实例,父类也会被加载, 而且,父类先被加载,子类后被加载
                 // AA aa2 = new AA();
                 //3. 使用类的静态成员时(静态属性,静态方法)
                 // System.out.println(Cat.n1);
        
                 //static代码块,是在类加载时,执行的,而且只会执行一次.
         //        DD dd = new DD();
         //        DD dd1 = new DD();
        
                 //普通的代码块,在创建对象实例时,会被隐式的调用。
                 // 被创建一次,就会调用一次。
                 // 如果只是使用类的静态成员时,普通代码块并不会执行
        
                 System.out.println(DD.n1);//8888, 静态模块块一定会执行
        
             }
         }
        
         class DD {
             public static int n1 = 8888;//静态属性
             //静态代码块
             static {
                 System.out.println("DD 的静态代码1被执行...");//
             }
             //普通代码块, 在new 对象时,被调用,而且是每创建一个对象,就调用一次
             //可以这样简单的,理解 普通代码块是构造器的补充
             {
                 System.out.println("DD 的普通代码块...");
             }
         }
        
         class Animal {
             //静态代码块
             static {
                 System.out.println("Animal 的静态代码1被执行...");//
             }
         }
        
         class Cat extends Animal {
        
             public static  int n1 = 999;//静态属性
        
             //静态代码块
             static {
                 System.out.println("Cat 的静态代码1被执行...");//
             }
         }
        
         class BB {
             //静态代码块
             static {
                 System.out.println("BB 的静态代码1被执行...");//1
             }
         }
        
         class AA extends BB {
        
        
             //静态代码块
             static {
                 System.out.println("AA 的静态代码1被执行...");//2
             }
         }
         //DD 的静态代码1被执行...
         //8888
        
    6. 创建一个对象时,在一个类调用顺序是:(重点,难点):

      1. ①调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)

      2. ②调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用)
        ③调用构造方法

      3. 代码示例

        1.  package com.hspedu.codeblock_;
          
           public class CodeBlockDetail02 {
               public static void main(String[] args) {
                   A a = new A();// (1) A 静态代码块01 (2) getN1被调用...(3)A 普通代码块01(4)getN2被调用...(5)A() 构造器被调用
               }
           }
          
           class A {
               { //普通代码块
                   System.out.println("A 普通代码块01");
               }
               private int n2 = getN2();//普通属性的初始化
          
          
               static { //静态代码块
                   System.out.println("A 静态代码块01");
               }
          
               //静态属性的初始化
               private static  int n1 = getN1();
          
               public static int getN1() {
                   System.out.println("getN1被调用...");
                   return 100;
               }
               public int getN2() { //普通方法/非静态方法
                   System.out.println("getN2被调用...");
                   return 200;
               }
          
               //无参构造器
               public A() {
                   System.out.println("A() 构造器被调用");
               }
          
           }
          
           输出结果:
           A 静态代码块01
           getN1被调用...
           A 普通代码块01
           getN2被调用...
           A() 构造器被调用
          
    7. 我们看一下创建一个子类对象时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:

      1. 父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
      2. 子类的静态代码块和静态属性(优先级一样,按定义顺序执行
      3. 父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
      4. 父类的构造方法
      5. 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
      6. 子类的构造方法
    8. 静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。

    9. 代码示例

      1.  package com.hspedu.codeblock_;
        
         public class CodeBlockDetail04 {
             public static void main(String[] args) {
                 //老师说明
                 //(1) 进行类的加载
                 //1.1 先加载 父类 A02 1.2 再加载 B02
                 //(2) 创建对象
                 //2.1 从子类的构造器开始
                 //new B02();//对象
        
                 new C02();
             }
         }
        
         class A02 { //父类
             private static int n1 = getVal01();
             static {
                 System.out.println("A02的一个静态代码块..");//(2)
             }
             {
                 System.out.println("A02的第一个普通代码块..");//(5)
             }
             public int n3 = getVal02();//普通属性的初始化
             public static int getVal01() {
                 System.out.println("getVal01");//(1)
                 return 10;
             }
        
             public int getVal02() {
                 System.out.println("getVal02");//(6)
                 return 10;
             }
        
             public A02() {//构造器
                 //隐藏
                 //super()
                 //普通代码和普通属性的初始化......
                 System.out.println("A02的构造器");//(7)
             }
        
         }
        
         class C02 {
             private int n1 = 100;
             private static  int n2 = 200;
        
             private void m1() {
        
             }
             private static void m2() {
        
             }
        
             static {
                 //静态代码块,只能调用静态成员
                 //System.out.println(n1);错误
                 System.out.println(n2);//ok
                 //m1();//错误
                 m2();
             }
             {
                 //普通代码块,可以使用任意成员
                 System.out.println(n1);
                 System.out.println(n2);//ok
                 m1();
                 m2();
             }
         }
        
         class B02 extends A02 { //
        
             private static int n3 = getVal03();
        
             static {
                 System.out.println("B02的一个静态代码块..");//(4)
             }
             public int n5 = getVal04();
             {
                 System.out.println("B02的第一个普通代码块..");//(9)
             }
        
             public static int getVal03() {
                 System.out.println("getVal03");//(3)
                 return 10;
             }
        
             public int getVal04() {
                 System.out.println("getVal04");//(8)
                 return 10;
             }
             //一定要慢慢的去品..
             public B02() {//构造器
                 //隐藏了
                 //super()
                 //普通代码块和普通属性的初始化...
                 System.out.println("B02的构造器");//(10)
                 // TODO Auto-generated constructor stub
             }
         }
         //200
         //100
         //200
        
    10. 代码示例

      1.  package com.hspedu.codeblock_;
        
         public class CodeBlockExercise02 {
         }
        
         class Sample
         {
             Sample(String s)
             {
                 System.out.println(s);
             }
             Sample()
             {
                 System.out.println("Sample默认构造函数被调用");
             }
         }
         class Test{
             Sample sam1=new Sample("sam1成员初始化");//
             static Sample sam=new Sample("静态成员sam初始化 ");//
             static{
                 System.out.println("static块执行");//
                 if(sam==null)System.out.println("sam is null");
             }
             Test()//构造器
             {
                 System.out.println("Test默认构造函数被调用");//
             }
             //主方法
             public static void  main(String  str[])
             {
                 Test a=new Test();//无参构造器
             }
        
         }
        
         输出结果:
         静态成员sam初始化 
         static块执行
         sam1成员初始化
         Test默认构造函数被调用
        

设计模式

  1. 单例设计模式

    1. 介绍
      1. 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(需要用到代码块的知识)
    2. 饿汉式
      1. 代码示例

        1.  package com.hspedu.single_;
          
           public class SingleTon01 {
          
               public static void main(String[] args) {
           //        GirlFriend xh = new GirlFriend("小红");
           //        GirlFriend xb = new GirlFriend("小白");
          
                   //通过方法可以获取对象
                   GirlFriend instance = GirlFriend.getInstance();
                   System.out.println(instance);
          
                   GirlFriend instance2 = GirlFriend.getInstance();
                   System.out.println(instance2);
          
                   System.out.println(instance == instance2);//T
                   //System.out.println(GirlFriend.n1);
          
                   //...
          
          
               }
          
           }
          
           //有一个类, GirlFriend
           //只能有一个女朋友
           class GirlFriend {
          
               private String name;
               //public static  int n1 = 100;
               //为了能够在静态方法中,返回 gf对象,需要将其修饰为static
               //對象,通常是重量級的對象, 餓漢式可能造成創建了對象,但是沒有使用.
               private static GirlFriend gf = new GirlFriend("小红红");
          
               //如何保障我们只能创建一个 GirlFriend 对象
               //步骤[单例模式-饿汉式]
               //1. 将构造器私有化
               //2. 在类的内部直接创建对象(该对象是static)
               //3. 提供一个公共的static方法,返回 gf对象
               private GirlFriend(String name) {
                   System.out.println("構造器被調用.");
                   this.name = name;
               }
          
               public static GirlFriend getInstance() {
                   return gf;
          
               }
          
               @Override
               public String toString() {
                   return "GirlFriend{" +
                           "name='" + name + '\'' +
                           '}';
               }
           }
          
           输出结果:
           構造器被調用.
           GirlFriend{name='小红红'}
           GirlFriend{name='小红红'}
           true
          
    3. 懒汉式
      1. 代码示例

        1.  package com.hspedu.single_;
          
           /**
            * 演示懶漢式的單例模式
            */
           public class SingleTon02 {
               public static void main(String[] args) {
                   //new Cat("大黃");
                   //System.out.println(Cat.n1);
                   Cat instance = Cat.getInstance();
                   System.out.println(instance);
          
          
                   //再次調用getInstance
                   Cat instance2 = Cat.getInstance();
                   System.out.println(instance2);
          
                   System.out.println(instance == instance2);//T
          
               }
           }
          
          
           //希望在程序運行過程中,只能創建一個Cat對象
           //使用單例模式
           class Cat {
               private String name;
               public static  int n1 = 999;
               private static Cat cat ; //默認是null
          
               //步驟
               //1.仍然構造器私有化
               //2.定義一個static靜態屬性對象
               //3.提供一個public的static方法,可以返回一個Cat對象
               //4.懶漢式,只有當用戶使用getInstance時,才返回cat對象, 後面再次調用時,會返回上次創建的cat對象
               //  從而保證了單例
               private Cat(String name) {
                   System.out.println("構造器調用...");
                   this.name = name;
               }
               public static Cat getInstance() {
          
                   if(cat == null) {//如果還沒有創建cat對象
                       cat = new Cat("小可愛");
                   }
                   return cat;
               }
          
               @Override
               public String toString() {
                   return "Cat{" +
                           "name='" + name + '\'' +
                           '}';
               }
           }
           输出结果:
           構造器調用...
           Cat{name='小可愛'}
           Cat{name='小可愛'}
           true
          
    4. 两者区别
      1. 二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建。
      2. 饿汉式不存在线程安全问题,懒汉式存在线程安全问题。(后面学习线程后,会完善一把)
      3. 饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题。
      4. 在我们javaSE标准类中,java.lang.Runtime就是经典的单例模式。
  2. 模板设计模式

    1. 介绍
      1. 抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。(需要用到抽象类的知识)

      2. 能解决的问题

        1. 当功能内部一部分实现是确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
          编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式.
    2. 代码示例
      1. 需求:

        1. 有多个类,完成不同的任务job
        2. 要求统计得到各自完成任务的时间
        3. 请编程实现
      2. 代码

        1.  AA.java:
           package com.hspedu.abstract_;
          
           public class AA extends Template {
          
               //计算任务
               //1+....+ 800000
               @Override
               public void job() { //实现Template的抽象方法job
          
                   long num = 0;
                   for (long i = 1; i <= 800000; i++) {
                       num += i;
                   }
               }
          
           //    public void job2() {
           //        //得到开始的时间
           //        long start = System.currentTimeMillis();
           //        long num = 0;
           //        for (long i = 1; i <= 200000; i++) {
           //            num += i;
           //        }
           //        //得的结束的时间
           //        long end = System.currentTimeMillis();
           //        System.out.println("AA 执行时间 " + (end - start));
           //    }
           }
           =================================================================================
           BB.java:
           package com.hspedu.abstract_;
          
           public class BB extends Template{
          
               public void job() {//这里也去,重写了Template的job方法
          
                   long num = 0;
                   for (long i = 1; i <= 80000; i++) {
                       num *= i;
                   }
          
               }
           }
           =================================================================================
           Template.java//模版文件
           package com.hspedu.abstract_;
          
           abstract public class Template { //抽象类-模板设计模式
          
               public abstract void job();//抽象方法
          
               public void calculateTime() {//实现方法,调用job方法
                   //得到开始的时间
                   long start = System.currentTimeMillis();
                   job(); //动态绑定机制
                   //得的结束的时间
                   long end = System.currentTimeMillis();
                   System.out.println("任务执行时间 " + (end - start));
               }
           }
           =================================================================================
           TestTemplate .java//运行文件
           package com.hspedu.abstract_;
          
           public class TestTemplate {
               public static void main(String[] args) {
          
                   AA aa = new AA();
                   aa.calculateTime(); //这里还是需要有良好的OOP基础,对多态
          
                   BB bb = new BB();
                   bb.calculateTime();//这里还是需要有良好的OOP基础,对多态
               }
           }
          
          

final关键字

  1. 介绍

    1. final 可以修饰类、属性、方法和局部变量.
      在某些情况下,程序员可能有以下需求,就会使用到final:

      1. 当不希望类被继承时,可以用final修饰.
      2. 当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰。
      3. 当不希望类的的某个属性的值被修改,可以用final修饰.
      4. 当不希望某个局部变量被修改,可以使用final修饰
  2. 代码示例

    1.  package com.hspedu.final_;
      
       public class Final01 {
           public static void main(String[] args) {
               E e = new E();
               //e.TAX_RATE = 0.09;
           }
       }
      
       //如果我们要求A类不能被其他类继承
       //可以使用final修饰 A类
       final class A { }
      
       //class B extends A {}
      
       class C {
           //如果我们要求hi不能被子类重写
           //可以使用final修饰 hi方法
           public final void hi() {}
       }
       class D extends C {
       //    @Override
       //    public void hi() {
       //        System.out.println("重写了C类的hi方法..");
       //    }
       }
      
       //当不希望类的的某个属性的值被修改,可以用final修饰
       class E {
           public final double TAX_RATE = 0.08;
       }
      
       //当不希望某个局部变量被修改,可以使用final修饰
       class F {
           public void cry() {
               //这时,NUM 也称为 局部常量
               final double NUM = 0.01;
               //NUM = 0.9;
               System.out.println("NUM=" + NUM);
           }
       }
       //编译成功
      
  3. 注意事项

    1. final修饰的属性又叫常量,一般用XX XX XX来命名

    2. final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一【选择一个位置赋初值即可】:

      1. 定义时:如 public final double TAX RATE=0.08;
      2. 在构造器中
      3. 在代码块中。
    3. 3)如果final修饰的属性是静态的,则初始化的位置只能是

      1. 定义时
      2. 在静态代码块不能在构造器中赋值。
    4. final类不能继承,但是可以实例化对象。[A2类]

    5. 如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承。[A3类]

    6. 代码示例

      1.  package com.hspedu.final_;
        
         public class FinalDetail01 {
             public static void main(String[] args) {
                 CC cc = new CC();
        
                 new EE().cal();
             }
         }
        
         class AA {
             /*
             1. 定义时:如 public final double TAX_RATE=0.08;
             2. 在构造器中
             3. 在代码块中
              */
             public final double TAX_RATE = 0.08;//1.定义时赋值
             public final double TAX_RATE2 ;
             public final double TAX_RATE3 ;
        
             public AA() {//构造器中赋值
                 TAX_RATE2 = 1.1;
             }
             {//在代码块赋值
                 TAX_RATE3 = 8.8;
             }
         }
        
         class BB {
             /*
             如果final修饰的属性是静态的,则初始化的位置只能是
             1 定义时  2 在静态代码块 不能在构造器中赋值。
              */
             public static final double TAX_RATE = 99.9;
             public static final double TAX_RATE2 ;
        
             static {
                 TAX_RATE2 = 3.3;
             }
        
        
         }
        
         //final类不能继承,但是可以实例化对象
         final class CC { }
        
        
         //如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承
         //即,仍然遵守继承的机制.
         class DD {
             public final void cal() {
                 System.out.println("cal()方法");
             }
         }
         class EE extends DD { }
         //cal()方法
        
    7. 一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法。

    8. final不能修饰构造方法(即构造器)

    9. final 和 static 往往搭配使用,效率更高,不会导致类加载.底层编译器做了优化
      处理。

    10. 包装类(Integer,Double,Float,Boolean等都是final),String也是final类。

    11. 注意事项

      1.  package com.hspedu.final_;
        
         public class FinalDetail02 {
             public static void main(String[] args) {
                 System.out.println(BBB.num);
                 System.out.println("==================");
                 System.out.println(BBB.num1);
        
                 //包装类,String 是final类,不能被继承
        
             }
         }
        
         //final 和 static 往往搭配使用,效率更高,不会导致类加载.底层编译器做了优化处理
         class BBB {
             public final static  int num = 10000;
             public static  int num1 = 10000;
             static {
                 System.out.println("BBB 静态代码块被执行");
             }
         }
         final class AAA{
             //一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法
             //public final void cry() {}
         }
         输出结果:
         10000
         ==================
         BBB 静态代码块被执行
         10000
        

抽象类

  1. 介绍

    1. 当父类的某些方法,需要声明,但是又不确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类
    2. 用abstract 关键字来修饰一个类时,这个类就叫抽象类
      访问修饰符 abstract 类名{
    3. 用abstract关键字来修饰一个方法时,这个方法就是抽象方法
      访问修饰符abstract 返回类型方法名(参数列表);//没有方法体
    4. 抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类()
    5. 抽象类,是考官比较爱问的知识点,在框架和设计模式使用较多
  2. 注意事项

    1. 抽象类不能被实例化

    2. 抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法

    3. 一旦类包含了abstract方法,则这个类必须声明为abstract

    4. abstract 只能修饰类和方法,不能修饰属性和其它的。

    5. 代码示例

      1.  package com.hspedu.abstract_;
        
         public class AbstractDetail01 {
             public static void main(String[] args) {
                 //抽象类,不能被实例化
                 //new A();
             }
         }
         //抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
         //,还可以有实现的方法。
         abstract class A {
             public void hi() {
                 System.out.println("hi");
             }
         }
         //一旦类包含了abstract方法,则这个类必须声明为abstract
         abstract class B {
             public abstract void hi();
         }
         //abstract 只能修饰类和方法,不能修饰属性和其它的
         class C {
            // public abstract int n1 = 1;
         }
         //成功运行
        
    6. 5)抽象类可以有任意成员【抽象类本质还是类】,比如:非抽象方法、构造器、静态属性等等
      6)抽象方法不能有主体,即不能实现.如abstract void aaa(){}
      7)如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类。

    7. 代码示例

      1.  package com.hspedu.abstract_;
        
         public class AbstractDetail01 {
             public static void main(String[] args) {
                 //抽象类,不能被实例化
                 //new A();
             }
         }
         //抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
         //,还可以有实现的方法。
         abstract class A {
             public void hi() {
                 System.out.println("hi");
             }
         }
         //一旦类包含了abstract方法,则这个类必须声明为abstract
         abstract class B {
             public abstract void hi();
         }
         //abstract 只能修饰类和方法,不能修饰属性和其它的
         class C {
            // public abstract int n1 = 1;
         }
         //成功编译
        

接口

  1. 介绍

    1. 接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。
    2. 接口是更加抽象的抽象的类,抽象类里的方法可以有方法体,接口里的所有方法都没有方法体【jdk7.0】。接口体现了程序设计的多态和高内聚低偶合的设计思想。
  2. 基本语法

    1. interface 接口名{
      属性;
      抽象方法;
      }
    2. class 类名 implements 接口{
      自己属性;
      自己方法;
      必须实现的接口方法;
      }
  3. 注意细节

    1. 接口不能被实例化

    2. 接口中所有的方法是public方法,接口中抽象方法,可以不用abstract修饰

    3. 一个普通类实现接口,就必须将该接口的所有方法都实现。

    4. 抽象类实现接口,可以不用实现接口的方法。

    5. 代码示例

      1.  package com.hspedu.interface_;
        
         public class InterfaceDetail01 {
             public static void main(String[] args) {
                 //new IA();
             }
         }
        
         //1.接口不能被实例化
         //2.接口中所有的方法是 public方法,  接口中抽象方法,可以不用abstract 修饰
         //3.一个普通类实现接口,就必须将该接口的所有方法都实现,可以使用alt+enter来解决
         //4.抽象类去实现接口时,可以不实现接口的抽象方法
         interface IA {
             void say();//修饰符 public protected 默认 private
             void hi();
         }
         class Cat implements IA{
             @Override
             public void say() {
        
             }
        
             @Override
             public void hi() {
        
             }
         }
         abstract class Tiger implements  IA {
        
         }
         //编译成功
        
    6. 一个类同时可以实现多个接口[举例]

    7. 接口中的属性,只能是final的,而且是 public static final 修饰符。比如:
      int a=1;实际上是 public static final int a=1;(必须初始化)

    8. 接口中属性的访问形式:接口名.属性名

    9. 接口不能继承其它的类,但是可以继承多个别的接口[举例]
      interface A extends B,C(}

    10. 接口的修饰符只能是public 和默认,这点和类的修饰符是一样的。

    11. 代码示例

      1.  package com.hspedu.interface_;
        
         public class InterfaceDetail02 {
             public static void main(String[] args) {
                 //老韩证明 接口中的属性,是 public static final
                 System.out.println(IB.n1);//说明n1 就是static
                 //IB.n1 = 30; 说明n1 是 final
             }
         }
         interface IB {
             //接口中的属性,只能是final的,而且是 public static final 修饰符
             int n1 = 10; //等价 public static final int n1 = 10;
             void hi();
         }
         interface IC {
             void say();
         }
         //接口不能继承其它的类,但是可以继承多个别的接口
         interface ID extends IB,IC {
         }
         //接口的修饰符 只能是 public 和默认,这点和类的修饰符是一样的
         interface IE{}
        
         //一个类同时可以实现多个接口
         class Pig implements IB,IC {
             @Override
             public void hi() {
             }
             @Override
             public void say() {
             }
         }
         //10
        
  4. 接口特性

    1. 在前面的Usb接口案例,UsbInterface usb,既可以接收手机对象,又可以接收相机对象,就体现了接口多态(接口引用可以指向实现了接口的类的对象)

      1.  package com.hspedu.interface_;
        
         public class InterfacePolyParameter {
             public static void main(String[] args) {
        
                 //接口的多态体现
                 //接口类型的变量 if01 可以指向 实现了IF接口类的对象实例
                 IF if01 = new Monster();
                 if01 = new Car();
        
                 //继承体现的多态
                 //父类类型的变量 a 可以指向 继承AAA的子类的对象实例
                 AAA a = new BBB();
                 a = new CCC();
             }
         }
        
         interface IF {}
         class Monster implements IF{}
         class Car implements  IF{}
        
         class AAA {
        
         }
         class BBB extends AAA {}
         class CCC extends AAA {}
         //成功编译
        
    2. 给Usb数组中,存放Phone和相机对象,Phone类还有一个特有的方法call(),请遍历Usb数组,如果是Phone对象,除了调用Usb接口定义的方法外,还需要调用Phone 特有方法 call.

      1.  package com.hspedu.interface_;
        
         public class InterfacePolyArr {
             public static void main(String[] args) {
        
                 //多态数组 -> 接口类型数组
                 Usb[] usbs = new Usb[2];
                 usbs[0] = new Phone_();
                 usbs[1] = new Camera_();
                 /*
                 给Usb数组中,存放 Phone  和  相机对象,Phone类还有一个特有的方法call(),
                 请遍历Usb数组,如果是Phone对象,除了调用Usb 接口定义的方法外,
                 还需要调用Phone 特有方法 call
                  */
                 for(int i = 0; i < usbs.length; i++) {
                     usbs[i].work();//动态绑定..
                     //和前面一样,我们仍然需要进行类型的向下转型
                     if(usbs[i] instanceof Phone_) {//判断他的运行类型是 Phone_
                         ((Phone_) usbs[i]).call();
                     }
                 }
        
             }
         }
        
         interface Usb{
             void work();
         }
         class Phone_ implements Usb {
             public void call() {
                 System.out.println("手机可以打电话...");
             }
        
             @Override
             public void work() {
                 System.out.println("手机工作中...");
             }
         }
         class Camera_ implements Usb {
        
             @Override
             public void work() {
                 System.out.println("相机工作中...");
             }
         }
         //手机工作中...
         //手机可以打电话...
         //相机工作中...
        
    3. 接口多态传递

      1.  package com.hspedu.interface_;
        
         /**
          * 演示多态传递现象
          */
         public class InterfacePolyPass {
             public static void main(String[] args) {
                 //接口类型的变量可以指向,实现了该接口的类的对象实例
                 IG ig = new Teacher();
                 //如果IG 继承了 IH 接口,而Teacher 类实现了 IG接口
                 //那么,实际上就相当于 Teacher 类也实现了 IH接口.
                 //这就是所谓的 接口多态传递现象.
                 IH ih = new Teacher();
             }
         }
        
         interface IH {
             void hi();
         }
         interface IG extends IH{ }
         class Teacher implements IG {
             @Override
             public void hi() {
             }
         }
        
        

内部类

  1. 介绍

    1. 个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。是我们类的第五大成员【思考:类的五大成员是哪些?[属性、方法、构造器、代码块、内部类]】,内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系,注意:内部类是学习的难点,同时也是重点,后面看底层源码时,有大量的内部类.
  2. 分类

    1. 定义类在局部位置(方法中/代码块)

      1. 局部内部类
      2. 匿名内部类
    2. 定义类在成员位置

      1. 成员内部类
      2. 静态内部类
  3. 局部内部类

    1. 使用
      1. 说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。

      2. 可以直接访问外部类的所有成员,包含私有的

      3. 不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final

      4. 作用域:仅仅在定义它的方法或代码块中。

      5. 局部内部类——访问——>外部类的成员[访问方式:直接访问]5.外部类—访问——>局部内部类的成员
        访问方式:创建对象,再访问(注意:必须在作用域内)

      6. 记住:

        1. 局部内部类定义在方法中/代码块
        2. 作用域在方法体或者代码块中
        3. 本质仍然是一个类
      7. 外部其他类———不能访问———>局部内部类(因为局部内部类地位是一个局部变量)

      8. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问【演示】

    2. 代码示例
      1.  package com.hspedu.innerclass;
         /**
          * 演示局部内部类的使用
          */
         public class LocalInnerClass {//
             public static void main(String[] args) {
                 //演示一遍
                 Outer02 outer02 = new Outer02();
                 outer02.m1();
                 System.out.println("outer02的hashcode=" + outer02);
             }
         }
        
        
         class Outer02 {//外部类
             private int n1 = 100;
             private void m2() {
                 System.out.println("Outer02 m2()");
             }//私有方法
             public void m1() {//方法
                 //1.局部内部类是定义在外部类的局部位置,通常在方法
                 //3.不能添加访问修饰符,但是可以使用final 修饰
                 //4.作用域 : 仅仅在定义它的方法或代码块中
                 final class Inner02 {//局部内部类(本质仍然是一个类)
                     //2.可以直接访问外部类的所有成员,包含私有的
                     private int n1 = 800;
                     public void f1() {
                         //5. 局部内部类可以直接访问外部类的成员,比如下面 外部类n1 和 m2()
                         //7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,
                         //   使用 外部类名.this.成员)去访问
                         //   老韩解读 Outer02.this 本质就是外部类的对象, 即哪个对象调用了m1, Outer02.this就是哪个对象
                         System.out.println("n1=" + n1 + " 外部类的n1=" + Outer02.this.n1);
                         System.out.println("Outer02.this hashcode=" + Outer02.this);
                         m2();
                     }
                 }
                 //6. 外部类在方法中,可以创建Inner02对象,然后调用方法即可
                 Inner02 inner02 = new Inner02();
                 inner02.f1();
             }
        
         }
         输出结果:
         n1=800 外部类的n1=100
         Outer02.this hashcode=com.hspedu.innerclass.Outer02@1b6d3586
         Outer02 m2()
         outer02的hashcode=com.hspedu.innerclass.Outer02@1b6d3586
        
  4. 匿名内部类

    1. 介绍
      1. 本质是类
      2. 内部类
      3. 该类没有名字
    2. 基本语法
      1. new 类或接口(参数列表){
        类体
        };
    3. 代码示例
      1. 示例一

        1.  package com.hspedu.innerclass;
          
          
           /**
            * 演示匿名内部类的使用
            */
           public class AnonymousInnerClass {
               public static void main(String[] args) {
                   Outer04 outer04 = new Outer04();
                   outer04.method();
               }
           }
          
           class Outer04 { //外部类
               private int n1 = 10;//属性
               public void method() {//方法
                   //基于接口的匿名内部类
                   //老韩解读
                   //1.需求: 想使用IA接口,并创建对象
                   //2.传统方式,是写一个类,实现该接口,并创建对象
                   //3.老韩需求是 Tiger/Dog 类只是使用一次,后面再不使用
                   //4. 可以使用匿名内部类来简化开发
                   //5. tiger的编译类型 ? IA
                   //6. tiger的运行类型 ? 就是匿名内部类  Outer04$1
                   /*
                       我们看底层 会分配 类名 Outer04$1
                       class Outer04$1 implements IA {
                           @Override
                           public void cry() {
                               System.out.println("老虎叫唤...");
                           }
                       }
                    */
                   //7. jdk底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1实例,并且把地址
                   //   返回给 tiger
                   //8. 匿名内部类使用一次,就不能再使用
                   IA tiger = new IA() {
                       @Override
                       public void cry() {
                           System.out.println("老虎叫唤...");
                       }
                   };
                   System.out.println("tiger的运行类型=" + tiger.getClass());
                   tiger.cry();
                   tiger.cry();
                   tiger.cry();
          
           //        IA tiger = new Tiger();
           //        tiger.cry();
          
                   //演示基于类的匿名内部类
                   //分析
                   //1. father编译类型 Father
                   //2. father运行类型 Outer04$2
                   //3. 底层会创建匿名内部类
                   /*
                       class Outer04$2 extends Father{
                           @Override
                           public void test() {
                               System.out.println("匿名内部类重写了test方法");
                           }
                       }
                    */
                   //4. 同时也直接返回了 匿名内部类 Outer04$2的对象
                   //5. 注意("jack") 参数列表会传递给 构造器
                   Father father = new Father("jack"){
          
                       @Override
                       public void test() {
                           System.out.println("匿名内部类重写了test方法");
                       }
                   };
                   System.out.println("father对象的运行类型=" + father.getClass());//Outer04$2
                   father.test();
          
                   //基于抽象类的匿名内部类
                   Animal animal = new Animal(){
                       @Override
                       void eat() {
                           System.out.println("小狗吃骨头...");
                       }
                   };
                   animal.eat();
               }
           }
          
           interface IA {//接口
               public void cry();
           }
           //class Tiger implements IA {
           //
           //    @Override
           //    public void cry() {
           //        System.out.println("老虎叫唤...");
           //    }
           //}
           //class Dog implements  IA{
           //    @Override
           //    public void cry() {
           //        System.out.println("小狗汪汪...");
           //    }
           //}
          
           class Father {//类
               public Father(String name) {//构造器
                   System.out.println("接收到name=" + name);
               }
               public void test() {//方法
               }
           }
          
           abstract class Animal { //抽象类
               abstract void eat();
           }
           输出结果:
           tiger的运行类型=class com.hspedu.innerclass.Outer04$1
           老虎叫唤...
           老虎叫唤...
           老虎叫唤...
           接收到name=jack
           father对象的运行类型=class com.hspedu.innerclass.Outer04$2
           匿名内部类重写了test方法
           小狗吃骨头...
          
      2. 示例二

        1.  package com.hspedu.innerclass;
          
           import com.hspedu.abstract_.AA;
          
           public class InnerClassExercise01 {
               public static void main(String[] args) {
          
                   //当做实参直接传递,简洁高效
                   f1(new IL() {
                       @Override
                       public void show() {
                           System.out.println("这是一副名画~~...");
                       }
                   });
                   //传统方法
                   System.out.println("=====================");
                   f1(new Picture());
          
               }
          
               //静态方法,形参是接口类型
               public static void f1(IL il) {
                   il.show();
                   System.out.println("12313");
               }
           }
           //接口
           interface IL {
               void show();
           }
           //类->实现IL => 编程领域 (硬编码)
           class Picture implements IL {
          
               @Override
               public void show() {
                   System.out.println("这是一副名画XX...");
               }
           }
           输出结果:
           这是一副名画~~...
           12313
           =====================
           这是一副名画XX...
           12313
          
  5. 使用细节
    1. 匿名内部类的语法比较奇特,请大家注意,因为匿名内部类既是一个类的定义同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点,因此可以调用匿名内部类方法。

    2. 可以直接访问外部类的所有成员,包含私有的

    3. 不能添加访问修饰符,因为它的地位就是一个局部变量。

    4. 作用域:仅仅在定义它的方法或代码块中。[过]

    5. 匿名内部类----访问----->外部类成员[访问方式:直接访问]

    6. 外部其他类——不能访问——>匿名内部类(因为匿名内部类地位是一个局部变量)

    7. 如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

    8. 代码实例

      1.  package com.hspedu.innerclass;
        
         public class AnonymousInnerClassDetail {
             public static void main(String[] args) {
        
                 Outer05 outer05 = new Outer05();
                 outer05.f1();
                 //外部其他类---不能访问----->匿名内部类
                 System.out.println("main outer05 hashcode=" + outer05);
             }
         }
        
         class Outer05 {
             private int n1 = 99;
             public void f1() {
                 //创建一个基于类的匿名内部类
                 //不能添加访问修饰符,因为它的地位就是一个局部变量
                 //作用域 : 仅仅在定义它的方法或代码块中
                 Person p = new Person(){
                     private int n1 = 88;
                     @Override
                     public void hi() {
                         //可以直接访问外部类的所有成员,包含私有的
                         //如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,
                         //默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问
                         System.out.println("匿名内部类重写了 hi方法 n1=" + n1 +
                                 " 外部内的n1=" + Outer05.this.n1 );
                         //Outer05.this 就是调用 f1的 对象
                         System.out.println("Outer05.this hashcode=" + Outer05.this);
                     }
                 };
                 p.hi();//动态绑定, 运行类型是 Outer05$1
        
                 //也可以直接调用, 匿名内部类本身也是返回对象
                 // class 匿名内部类 extends Person {}
         //        new Person(){
         //            @Override
         //            public void hi() {
         //                System.out.println("匿名内部类重写了 hi方法,哈哈...");
         //            }
         //            @Override
         //            public void ok(String str) {
         //                super.ok(str);
         //            }
         //        }.ok("jack");
        
        
             }
         }
        
         class Person {//类
             public void hi() {
                 System.out.println("Person hi()");
             }
             public void ok(String str) {
                 System.out.println("Person ok() " + str);
             }
         }
         //抽象类/接口...
         输出结果:
         匿名内部类重写了 hi方法 n1=88 外部内的n1=99
         Outer05.this hashcode=com.hspedu.innerclass.Outer05@1b6d3586
         main outer05 hashcode=com.hspedu.innerclass.Outer05@1b6d3586
        
  6. 成员内部类

    1. 说明
      1. 可以直接访问外部类所有成员,包含私有的
      2. 可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。
      3. 作用域MemberlnnerClass01.java 和外部类的其他成员一样,为整个类体比如前面案例,在外部类的成员方法中创建成员内部类对象,再调用方法.
      4. 成员内部类——访问——>外部类成员(比如:属性)[访问方式:直接访问](说明)
      5. 外部类——访问———>成员内部类(说明)访问方式:创建对象,再访问
      6. 外部其他类——访问——>成员内部类
      7. 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
    2. 代码示例
      1.  package com.hspedu.innerclass;
        
         public class MemberInnerClass01 {
             public static void main(String[] args) {
                 Outer08 outer08 = new Outer08();
                 outer08.t1();
        
                 //外部其他类,使用成员内部类的三种方式
                 //老韩解读
                 // 第一种方式
                 // outer08.new Inner08(); 相当于把 new Inner08()当做是outer08成员
                 // 这就是一个语法,不要特别的纠结.
                 Outer08.Inner08 inner08 = outer08.new Inner08();
                 inner08.say();
                 // 第二方式 在外部类中,编写一个方法,可以返回 Inner08对象
                 Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
                 inner08Instance.say();
        
        
             }
         }
        
         class Outer08 { //外部类
             private int n1 = 10;
             public String name = "张三";
        
             private void hi() {
                 System.out.println("hi()方法...");
             }
        
             //1.注意: 成员内部类,是定义在外部内的成员位置上
             //2.可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
             public class Inner08 {//成员内部类
                 private double sal = 99.8;
                 private int n1 = 66;
                 public void say() {
                     //可以直接访问外部类的所有成员,包含私有的
                     //如果成员内部类的成员和外部类的成员重名,会遵守就近原则.
                     //,可以通过  外部类名.this.属性 来访问外部类的成员
                     System.out.println("n1 = " + n1 + " name = " + name + " 外部类的n1=" + Outer08.this.n1);
                     hi();
                 }
             }
             //方法,返回一个Inner08实例
             public Inner08 getInner08Instance(){
                 return new Inner08();
             }
        
        
             //写方法
             public void t1() {
                 //使用成员内部类
                 //创建成员内部类的对象,然后使用相关的方法
                 Inner08 inner08 = new Inner08();
                 inner08.say();
                 System.out.println(inner08.sal);
             }
         }
         输出结果:
         n1 = 66 name = 张三 外部类的n1=10
         hi()方法...
         99.8
         n1 = 66 name = 张三 外部类的n1=10
         hi()方法...
         n1 = 66 name = 张三 外部类的n1=10
         hi()方法...
        
  7. 静态内部类

    1. 使用细节
      1. 说明:静态内部类是定义在外部类的成员位置,并且有static修饰
      2. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
      3. 可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是 一个成员。
      4. 作用域:同其他的成员,为整个类体
      5. 静态内部类——访问——>外部类(比如:静态属性)[访问方式:直接访问所有静态成员]
      6. 外部类——访问——>静态内部类访问方式:创建对象,再访问
      7. 外部其他类——访问——>静态内部类
      8. 如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问
    2. 代码示例
      1.  package com.hspedu.innerclass;
        
         public class StaticInnerClass01 {
             public static void main(String[] args) {
                 Outer10 outer10 = new Outer10();
                 outer10.m1();
        
                 //外部其他类 使用静态内部类
                 //方式1
                 //因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
                 Outer10.Inner10 inner10 = new Outer10.Inner10();
                 inner10.say();
                 //方式2
                 //编写一个方法,可以返回静态内部类的对象实例.
                 Outer10.Inner10 inner101 = outer10.getInner10();
                 System.out.println("============");
                 inner101.say();
        
                 Outer10.Inner10 inner10_ = Outer10.getInner10_();
                 System.out.println("************");
                 inner10_.say();
             }
         }
        
         class Outer10 { //外部类
             private int n1 = 10;
             private static String name = "张三";
             private static void cry() {}
             //Inner10就是静态内部类
             //1. 放在外部类的成员位置
             //2. 使用static 修饰
             //3. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
             //4. 可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
             //5. 作用域 :同其他的成员,为整个类体
             static class Inner10 {
                 private static String name = "123教育";
                 public void say() {
                     //如果外部类和静态内部类的成员重名时,静态内部类访问的时,
                     //默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.成员)
                     System.out.println(name + " 外部类name= " + Outer10.name);
                     cry();
                 }
             }
        
             public void m1() { //外部类---访问------>静态内部类 访问方式:创建对象,再访问
                 Inner10 inner10 = new Inner10();
                 inner10.say();
             }
        
             public Inner10 getInner10() {
                 return new Inner10();
             }
        
             public static Inner10 getInner10_() {
                 return new Inner10();
             }
         }
         输出结果:
         132教育 外部类name= 张三
         132教育 外部类name= 张三
         ============
         132教育 外部类name= 张三
         ************
         132教育 外部类name= 张三
        

自定义枚举类

  1. 介绍

    1. 枚举类是一种特殊的类,用于定义一组固定的常量,这些常量通常代表一组相关的、预定义的值,每个值都是该枚举类的一个实例。
  2. 使用

    1. 不需要提供setXxx方法,因为枚举对象值通常为只读.

    2. 对枚举对象/属性使用final+static共同修饰,实现底层优化.

    3. 枚举对象名通常使用全部大写,常量的命名规范.

    4. 枚举对象根据需要,也可以有多个属性

      1. 小结

        1. 构造器私有化
        2. 本类内部创建一组对象
        3. 对外暴露对象(通过为对象添加public final static修饰符)
        4. 可以提供get方法,但是不要提供set方法
    5. 代码示例

      1.  package com.hspedu.enum_;
        
         public class Enumeration02 {
             public static void main(String[] args) {
                 System.out.println(Season.AUTUMN);
                 System.out.println(Season.SPRING);
             }
         }
        
         //演示字定义枚举实现
         class Season {//类
             private String name;
             private String desc;//描述
        
             //定义了四个对象, 固定.
             public static final Season SPRING = new Season("春天", "温暖");
             public static final Season WINTER = new Season("冬天", "寒冷");
             public static final Season AUTUMN = new Season("秋天", "凉爽");
             public static final Season SUMMER = new Season("夏天", "炎热");
        
        
             //1. 将构造器私有化,目的防止 直接 new
             //2. 去掉setXxx方法, 防止属性被修改
             //3. 在Season 内部,直接创建固定的对象
             //4. 优化,可以加入 final 修饰符
             private Season(String name, String desc) {
                 this.name = name;
                 this.desc = desc;
             }
        
             public String getName() {
                 return name;
             }
        
             public String getDesc() {
                 return desc;
             }
        
             @Override
             public String toString() {
                 return "Season{" +
                         "name='" + name + '\'' +
                         ", desc='" + desc + '\'' +
                         '}';
             }
         }
         //Season{name='秋天', desc='凉爽'}
         //Season{name='春天', desc='温暖'}
        

enum枚举类

  1. 注意事项

    1. 当我们使用enum关键字开发一个枚举类是,默认会继承Enum类,而且是一个final类

    2. 传统的 public static final Season2 SPRING = new Season2(“春天”,“温暖“);简化成SPRING(”春天“,”温暖”),这里必须知道,它调用的是哪个构造器

    3. 如果使用无参构造器创建枚举对象,则实参列表和小括号都可以省略

    4. 枚举对象必须放在枚举类的行首

    5. 当有多个枚举对象时,使用","间隔,最后有一个分号结尾

    6.  package com.hspedu.enum_;
      
       public class Enumeration03 {
           public static void main(String[] args) {
               System.out.println(Season2.AUTUMN);
               System.out.println(Season2.SUMMER);
           }
       }
       //演示使用enum关键字来实现枚举类
       enum  Season2 {//类
      
      
           //定义了四个对象, 固定.
       //    public static final Season SPRING = new Season("春天", "温暖");
       //    public static final Season WINTER = new Season("冬天", "寒冷");
       //    public static final Season AUTUMN = new Season("秋天", "凉爽");
       //    public static final Season SUMMER = new Season("夏天", "炎热");
           //如果使用了enum 来实现枚举类
           //1. 使用关键字 enum 替代 class
           //2. public static final Season SPRING = new Season("春天", "温暖") 直接使用
           //   SPRING("春天", "温暖") 解读 常量名(实参列表)
           //3. 如果有多个常量(对象), 使用 ,号间隔即可
           //4. 如果使用enum 来实现枚举,要求将定义常量对象,写在前面
           //5. 如果我们使用的是无参构造器,创建常量对象,则可以省略 ()
           SPRING("春天", "温暖"), WINTER("冬天", "寒冷"), AUTUMN("秋天", "凉爽"),
           SUMMER("夏天", "炎热")/*, What()*/;
      
           private String name;
           private String desc;//描述
      
           private Season2() {//无参构造器
      
           }
      
           private Season2(String name, String desc) {
               this.name = name;
               this.desc = desc;
           }
      
           public String getName() {
               return name;
           }
      
           public String getDesc() {
               return desc;
           }
      
           @Override
           public String toString() {
               return "Season{" +
                       "name='" + name + '\'' +
                       ", desc='" + desc + '\'' +
                       '}';
           }
       }
       //Season{name='秋天', desc='凉爽'}
       //Season{name='夏天', desc='炎热'}
      
  2. enum常用方法

    1. toString:Enum类已经重写过了,返回的是当前对象 名,子类可以重写该方法,用于返回对象的属性信息

    2. name:返回当前对象名(常量名),子类中不能重写

    3. ordinal:返回当前对象的位置号,默认从0开始

    4. values:返回当前枚举类中所有的常量

    5. valueOf:将字符串转换成枚举对象,要求字符串必须 为已有的常量名,否则报异常!

    6. compareTo:比较两个枚举常量,比较的就是编号!

    7. 代码示例

      1.  package com.hspedu.enum_;
        
         /**
          * @author 韩顺平
          * @version 1.0
          * 演示Enum类的各种方法的使用
          */
         public class EnumMethod {
             public static void main(String[] args) {
                 //使用Season2 枚举类,来演示各种方法
                 Season2 autumn = Season2.AUTUMN;
        
                 //输出枚举对象的名字
                 System.out.println(autumn.name());
                 //ordinal() 输出的是该枚举对象的次序/编号,从0开始编号
                 //AUTUMN 枚举对象是第三个,因此输出 2
                 System.out.println(autumn.ordinal());
                 //从反编译可以看出 values方法,返回 Season2[]
                 //含有定义的所有枚举对象
                 Season2[] values = Season2.values();
                 System.out.println("===遍历取出枚举对象(增强for)====");
                 for (Season2 season: values) {//增强for循环
                     System.out.println(season);
                 }
        
                 //valueOf:将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则报异常
                 //执行流程
                 //1. 根据你输入的 "AUTUMN" 到 Season2的枚举对象去查找
                 //2. 如果找到了,就返回,如果没有找到,就报错
                 Season2 autumn1 = Season2.valueOf("AUTUMN");
                 System.out.println("autumn1=" + autumn1);
                 System.out.println(autumn == autumn1);
        
                 //compareTo:比较两个枚举常量,比较的就是编号
                 //老韩解读
                 //1. 就是把 Season2.AUTUMN 枚举对象的编号 和 Season2.SUMMER枚举对象的编号比较
                 //2. 看看结果
                 /*
                 public final int compareTo(E o) {
        
                     return self.ordinal - other.ordinal;
                 }
                 Season2.AUTUMN的编号[2] - Season2.SUMMER的编号[3]
                  */
                 System.out.println(Season2.AUTUMN.compareTo(Season2.SUMMER));
        
                 //补充了一个增强for
         //        int[] nums = {1, 2, 9};
         //        //普通的for循环
         //        System.out.println("=====普通的for=====");
         //        for (int i = 0; i < nums.length; i++) {
         //            System.out.println(nums[i]);
         //        }
         //        System.out.println("=====增强的for=====");
         //        //执行流程是 依次从nums数组中取出数据,赋给i, 如果取出完毕,则退出for
         //        for(int i : nums) {
         //            System.out.println("i=" + i);
         //        }
             }
         }
        
         enum  Season2 {//类
        
        
             //定义了四个对象, 固定.
         //    public static final Season SPRING = new Season("春天", "温暖");
         //    public static final Season WINTER = new Season("冬天", "寒冷");
         //    public static final Season AUTUMN = new Season("秋天", "凉爽");
         //    public static final Season SUMMER = new Season("夏天", "炎热");
             //如果使用了enum 来实现枚举类
             //1. 使用关键字 enum 替代 class
             //2. public static final Season SPRING = new Season("春天", "温暖") 直接使用
             //   SPRING("春天", "温暖") 解读 常量名(实参列表)
             //3. 如果有多个常量(对象), 使用 ,号间隔即可
             //4. 如果使用enum 来实现枚举,要求将定义常量对象,写在前面
             //5. 如果我们使用的是无参构造器,创建常量对象,则可以省略 ()
             SPRING("春天", "温暖"), WINTER("冬天", "寒冷"), AUTUMN("秋天", "凉爽"),
             SUMMER("夏天", "炎热")/*, What()*/;
        
             private String name;
             private String desc;//描述
        
             private Season2() {//无参构造器
        
             }
        
             private Season2(String name, String desc) {
                 this.name = name;
                 this.desc = desc;
             }
        
             public String getName() {
                 return name;
             }
        
             public String getDesc() {
                 return desc;
             }
        
             @Override
             public String toString() {
                 return "Season{" +
                         "name='" + name + '\'' +
                         ", desc='" + desc + '\'' +
                         '}';
             }
         }
         输出结果:
         AUTUMN
         2
         ===遍历取出枚举对象(增强for)====
         Season{name='春天', desc='温暖'}
         Season{name='冬天', desc='寒冷'}
         Season{name='秋天', desc='凉爽'}
         Season{name='夏天', desc='炎热'}
         autumn1=Season{name='秋天', desc='凉爽'}
         true
         -1
        

注解

  1. 介绍

    1. 注解(Annotation)也被称为元数据(Metadata),用于修饰解释 包、类、方法、属性、构造器、局部变量等数据信息。
    2. 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。
    3. 在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替javaEE旧版中所遗留的繁冗代码和XML配置等。
    4. 注解可写可不写,但不能多写
  2. Annotation介绍

    1. 使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成一个修饰符使用。用于修饰它支持的程序元素

    2. 三个基本的 Annotation:

      1. @Override: 限定某个方法,是重写父类方法, 该注解只能用于方法
      2. @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
      3. @SuppressWarnings: 抑制编译器警告
  3. Override代码示例
    1.  package com.hspedu.annotation_;
      
       public class Override_ {
           public static void main(String[] args) {
      
           }
       }
       class Father{//父类
      
           public void fly(){
               int i = 0;
               System.out.println("Father fly...");
           }
           public void say(){}
      
       }
      
       class Son extends Father {//子类
           //解读
           //1. @Override 注解放在fly方法上,表示子类的fly方法时重写了父类的fly
           //2. 这里如果没有写 @Override 还是重写了父类fly
           //3. 如果你写了@Override注解,编译器就会去检查该方法是否真的重写了父类的
           //   方法,如果的确重写了,则编译通过,如果没有构成重写,则编译错误
           //4. 看看 @Override的定义
           //   解读: 如果发现 @interface 表示一个 注解类
           /*
               @Target(ElementType.METHOD)
               @Retention(RetentionPolicy.SOURCE)
               public @interface Override {
               }
            */
           @Override   //说明
           public void fly() {
               System.out.println("Son fly....");
           }
           @Override
           public void say() {}
       }
       //编译成功
      
  4. Deprecated代码示例
    1.  package com.hspedu.annotation_;
      
       public class Deprecated_ {
           public static void main(String[] args) {
               A a = new A();
               a.hi();
               System.out.println(a.n1);
           }
       }
      
       //解读
       //1. @Deprecated 修饰某个元素, 表示该元素已经过时
       //2. 即不在推荐使用,但是仍然可以使用
       //3. 查看 @Deprecated 注解类的源码
       //4. 可以修饰方法,类,字段, 包, 参数  等等
       //5. @Deprecated 可以做版本升级过渡使用
       /*
       @Documented
       @Retention(RetentionPolicy.RUNTIME)
       @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
       public @interface Deprecated {
       }
        */
       @Deprecated
       class A {
           @Deprecated
           public int n1 = 10;
           @Deprecated
           public void hi(){
      
           }
       }
       //编译成功
      
  5. SuppressWarnings代码示例
    1.  package com.hspedu.annotation_;
      
       import java.util.ArrayList;
       import java.util.List;
      
      
       @SuppressWarnings({"rawtypes", "unchecked", "unused"})
       public class SuppressWarnings_ {
      
           //解读
           //1. 当我们不希望看到这些警告的时候,可以使用 SuppressWarnings注解来抑制警告信息
           //2. 在{""} 中,可以写入你希望抑制(不显示)警告信息
           //3. 可以指定的警告类型有
           //          all,抑制所有警告
           //          boxing,抑制与封装/拆装作业相关的警告
           //        //cast,抑制与强制转型作业相关的警告
           //        //dep-ann,抑制与淘汰注释相关的警告
           //        //deprecation,抑制与淘汰的相关警告
           //        //fallthrough,抑制与switch陈述式中遗漏break相关的警告
           //        //finally,抑制与未传回finally区块相关的警告
           //        //hiding,抑制与隐藏变数的区域变数相关的警告
           //        //incomplete-switch,抑制与switch陈述式(enum case)中遗漏项目相关的警告
           //        //javadoc,抑制与javadoc相关的警告
           //        //nls,抑制与非nls字串文字相关的警告
           //        //null,抑制与空值分析相关的警告
           //        //rawtypes,抑制与使用raw类型相关的警告
           //        //resource,抑制与使用Closeable类型的资源相关的警告
           //        //restriction,抑制与使用不建议或禁止参照相关的警告
           //        //serial,抑制与可序列化的类别遗漏serialVersionUID栏位相关的警告
           //        //static-access,抑制与静态存取不正确相关的警告
           //        //static-method,抑制与可能宣告为static的方法相关的警告
           //        //super,抑制与置换方法相关但不含super呼叫的警告
           //        //synthetic-access,抑制与内部类别的存取未最佳化相关的警告
           //        //sync-override,抑制因为置换同步方法而遗漏同步化的警告
           //        //unchecked,抑制与未检查的作业相关的警告
           //        //unqualified-field-access,抑制与栏位存取不合格相关的警告
           //        //unused,抑制与未用的程式码及停用的程式码相关的警告
           //4. 关于SuppressWarnings 作用范围是和你放置的位置相关
           //   比如 @SuppressWarnings放置在 main方法,那么抑制警告的范围就是 main
           //   通常我们可以放置具体的语句, 方法, 类.
           //5.  看看 @SuppressWarnings 源码
           //(1) 放置的位置就是 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE
           //(2) 该注解类有数组 String[] values() 设置一个数组比如 {"rawtypes", "unchecked", "unused"}
           /*
               @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
                   @Retention(RetentionPolicy.SOURCE)
                   public @interface SuppressWarnings {
      
                       String[] value();
               }
            */
           public static void main(String[] args) {
               List list = new ArrayList();
               list.add("jack");
               list.add("tom");
               list.add("mary");
               int i;
               System.out.println(list.get(1));
      
           }
      
           public void f1() {
       //        @SuppressWarnings({"rawtypes"})
               List list = new ArrayList();
      
      
               list.add("jack");
               list.add("tom");
               list.add("mary");
       //        @SuppressWarnings({"unused"})
               int i;
               System.out.println(list.get(1));
           }
       }
       //tom
      

异常

  1. 概念

    1. Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常)

    2. 执行过程中所发生的异常事件可分为两大类

      1. Error(错误) :Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError[栈溢出]和OOM(out of memory),Error 是严重错误,程序会崩溃。
      2. Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问,试图读取不存在的文件,网络连接中断等等,Exception分为两大类:运行时异常[程序运行时,发生的异常]和编译时异常[编程时,编译器检查出的异常]。
  2. 异常体系图

    1. 运行时异常

      1. NullPointerException 空指针异常
      2. ArithmeticException 数学运算异常
      3. ArrayIndexOutOfBoundsException 数组下标越界异常
      4. ClassCastException 类型转换异常
      5. NumberFormatException 数字格式不正确异常[]
    2. 编译时异常

      1. SQLException/操作数据库时,查询表可能发生异常
      2. IOException/操作文件时,发生的异常
        FileNotFoundException/当操作一个不存在的文件时,发生异常
      3. ClassNotFoundException/加载类,而该类不存在时,异常
      4. EOFException/操作文件,到文件末尾,发生异常
      5. IllegalArguementException/参数异常
  3. 异常处理

    1. 介绍
      1. 异常处理就是当异常发生时,对异常处理的方式
    2. 方式
      1. try-catch-finally

        1. Java提供try和catch块来处理异常。try块用于包含可能出错的代码。catch块用于处理try块中发生的异常。可以根据需要在程序中有多个try.catch块。
      2. throws

        1. 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
        2. 在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
      3. throws与throw区别

        1. 意义位置后面跟的东西
          throws异常处理的一种方式方法声明处异常类型
          throw手动生成异常对象的关键字方法体中异常对象
    3. try-catch-finally使用细节
      1. 如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块

      2. 如果异常没有发生,则顺序执行try的代码块,不会进入到catch.

      3. 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等)
        则使用如下代码—finally{}

      4. 可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(Exception 在后,NullPointerException在 前),如果发生异常,只会匹配一个catch

      5. 代码示例

        1.  package com.hspedu.try_;
          
           public class TryCatchDetail02 {
               public static void main(String[] args) {
          
                   //老韩解读
                   //1.如果try代码块有可能有多个异常
                   //2.可以使用多个catch 分别捕获不同的异常,相应处理
                   //3.要求子类异常写在前面,父类异常写在后面
                   try {
                       Person person = new Person();
                       //person = null;
                       System.out.println(person.getName());//NullPointerException
                       int n1 = 10;
                       int n2 = 0;
                       int res = n1 / n2;//ArithmeticException
                   } catch (NullPointerException e) {
                       System.out.println("空指针异常=" + e.getMessage());
                   } catch (ArithmeticException e) {
                       System.out.println("算术异常=" + e.getMessage());
                   } catch (Exception e) {
                       System.out.println(e.getMessage());
                   } finally {
                   }
          
          
               }
           }
          
           class Person {
               private String name = "jack";
          
               public String getName() {
                   return name;
               }
           }
           //jack
           //算术异常=/ by zero
          
    4. throws使用细节
      1. 对于编译异常,程序中必须处理,比如 try—catch 或者 throws

      2. 对于运行时异常,程序中如果没有处理,默认就是throws的方式处理[举例]

      3. 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型[举例]

      4. 在throws 过程中,如果有方法 try—catch,就相当于处理异常,就可以不必throws

      5. 代码示例

        1.  package com.hspedu.throws_;
          
           import java.io.FileInputStream;
           import java.io.FileNotFoundException;
          
          
           public class ThrowsDetail {
               public static void main(String[] args) {
                   f2();
               }
          
               public static void f2() /*throws ArithmeticException*/ {
                   //1.对于编译异常,程序中必须处理,比如 try-catch 或者 throws
                   //2.对于运行时异常,程序中如果没有处理,默认就是throws的方式处理
          
                   int n1 = 10;
                   int n2 = 0;
           //        double res = n1 / n2;  会编译报错
               }
          
               public static void f1() throws FileNotFoundException {
                   //这里大家思考问题 调用f3() 报错
                   //解读
                   //1. 因为f3() 方法抛出的是一个编译异常
                   //2. 即这时,就要f1() 必须处理这个编译异常
                   //3. 在f1() 中,要么 try-catch-finally ,或者继续throws 这个编译异常
                   f3(); // 抛出异常
               }
               public static void f3() throws FileNotFoundException {
                   FileInputStream fis = new FileInputStream("d://aa.txt");
               }
          
               public static void f4() {
                   //解读:
                   //1. 在f4()中调用方法f5() 是OK
                   //2. 原因是f5() 抛出的是运行异常
                   //3. 而java中,并不要求程序员显示处理,因为有默认处理机制
                   f5();
               }
               public static void f5() throws ArithmeticException {
          
               }
           }
          
           class Father { //父类
               public void method() throws RuntimeException {
               }
           }
          
           class Son extends Father {//子类
               //3. 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,
               //   所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常类型的子类型
               //4. 在throws 过程中,如果有方法 try-catch , 就相当于处理异常,就可以不必throws
               @Override
               public void method() throws ArithmeticException {
               }
           }
           //编译成功
          
  4. 自定义异常

    1. 概念
      1. 当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。
    2. 步骤
      1. 定义类:自定义异常类名(程序员自己写)继承Exception或RuntimeException
      2. 如果继承Exception,属于编译异常
      3. 如果继承RuntimeException,属于运行异常(一般来说,继承RuntimeException)
    3. 代码示例
      1.  package com.hspedu.customexception_;
        
         public class CustomException {
             public static void main(String[] args) /*throws AgeException*/ {
        
                 int age = 180;
                 //要求范围在 18 – 120 之间,否则抛出一个自定义异常
                 if(!(age >= 18 && age <= 120)) {
                     //这里我们可以通过构造器,设置信息
                     throw new AgeException("年龄需要在 18~120之间");
                 }
                 System.out.println("你的年龄范围正确.");
             }
         }
         //自定义一个异常
         //老韩解读
         //1. 一般情况下,我们自定义异常是继承 RuntimeException
         //2. 即把自定义异常做成 运行时异常,好处时,我们可以使用默认的处理机制
         //3. 即比较方便
         class AgeException extends RuntimeException {
             public AgeException(String message) {//构造器
                 super(message);
             }
         }
         //运行出错
        

包装类

  1. 介绍

    1. jdk5前的手动装箱和拆箱方式,装箱:基本类型—>包装类型,反之,拆箱
    2. jdk5以后(含jdk5)的自动装箱和拆箱方式
    3. 自动装箱底层调用的是valueOf方法,比如Integer.valueOf()
  2. 代码示例

    1.  package com.hspedu.wrapper;
      
       public class Integer01 {
           public static void main(String[] args) {
               //演示int <--> Integer 的装箱和拆箱
               //jdk5前是手动装箱和拆箱
               //手动装箱 int->Integer
               int n1 = 100;
               Integer integer = new Integer(n1);
               Integer integer1 = Integer.valueOf(n1);
      
               //手动拆箱
               //Integer -> int
               int i = integer.intValue();
      
               //jdk5后,就可以自动装箱和自动拆箱
               int n2 = 200;
               //自动装箱 int->Integer
               Integer integer2 = n2; //底层使用的是 Integer.valueOf(n2)
               //自动拆箱 Integer->int
               int n3 = integer2; //底层仍然使用的是 intValue()方法
           }
       }
       //编译成功
      
  3. 包装类的常用方法

    1. integer和string类型相互转换
      1. 代码示例

        1.  package com.hspedu.wrapper;
          
           public class WrapperVSString {
               public static void main(String[] args) {
                   //包装类(Integer)->String
                   Integer i = 100;//自动装箱
                   //方式1
                   String str1 = i + "";
                   //方式2
                   String str2 = i.toString();
                   //方式3
                   String str3 = String.valueOf(i);
          
                   //String -> 包装类(Integer)
                   String str4 = "12345";
                   Integer i2 = Integer.parseInt(str4);//使用到自动装箱
                   Integer i3 = new Integer(str4);//构造器
          
                   System.out.println("编译成功");
          
               }
           }
           //编译成功
          
    2. 常用方法
      1.  package com.hspedu.wrapper;
        
         public class WrapperMethod {
             public static void main(String[] args) {
                 System.out.println(Integer.MIN_VALUE); //返回最小值
                 System.out.println(Integer.MAX_VALUE);//返回最大值
        
                 System.out.println(Character.isDigit('a'));//判断是不是数字
                 System.out.println(Character.isLetter('a'));//判断是不是字母
                 System.out.println(Character.isUpperCase('a'));//判断是不是大写
                 System.out.println(Character.isLowerCase('a'));//判断是不是小写
        
                 System.out.println(Character.isWhitespace('a'));//判断是不是空格
                 System.out.println(Character.toUpperCase('a'));//转成大写
                 System.out.println(Character.toLowerCase('A'));//转成小写
        
             }
         }
         输出结果:
         -2147483648
         2147483647
         false
         true
         false
         true
         false
         A
         a
        
    3. integer类
      1.  package com.hspedu.wrapper;
        
         public class WrapperExercise03 {
             public static void main(String[] args) {
                 //示例一
                 Integer i1 = new Integer(127);
                 Integer i2 = new Integer(127);
                 System.out.println(i1 == i2);//F
         //示例二
                 Integer i3 = new Integer(128);
                 Integer i4 = new Integer(128);
                 System.out.println(i3 == i4);//F
        
         //示例三
                 Integer i5 = 127;//底层Integer.valueOf(127)
                 Integer i6 = 127;//-128~127
                 System.out.println(i5 == i6); //T
         //示例四
                 Integer i7 = 128;
                 Integer i8 = 128;
                 System.out.println(i7 == i8);//F
         //示例五
                 Integer i9 = 127; //Integer.valueOf(127)
                 Integer i10 = new Integer(127);
                 System.out.println(i9 == i10);//F
        
                 //示例六
                 Integer i11=127;
                 int i12=127;
         //只有有基本数据类型,判断的是
         //值是否相同
                 System.out.println(i11==i12); //T
         //示例七
                 Integer i13=128;
                 int i14=128;
                 System.out.println(i13==i14);//T
        
        
             }
         }
         输出结果:
         false
         false
         true
         false
         false
         true
         true
        
    4. 大数处理方案
      1. BigInteger和BigDecimal常见方法

        1. bigdecimal示例

          package com.hspedu.bignum;
          
          import java.math.BigDecimal;
          
          public class BigDecimal_ {
              public static void main(String[] args) {
                  //当我们需要保存一个精度很高的数时,double 不够用
                  //可以是 BigDecimal
          //        double d = 1999.11111111111999999999999977788d;
          //        System.out.println(d);
                  BigDecimal bigDecimal = new BigDecimal("1999.11");
                  BigDecimal bigDecimal2 = new BigDecimal("3");
                  System.out.println(bigDecimal);
          
                  //老韩解读
                  //1. 如果对 BigDecimal进行运算,比如加减乘除,需要使用对应的方法
                  //2. 创建一个需要操作的 BigDecimal 然后调用相应的方法即可
                  System.out.println(bigDecimal.add(bigDecimal2));
                  System.out.println(bigDecimal.subtract(bigDecimal2));
                  System.out.println(bigDecimal.multiply(bigDecimal2));
                  //System.out.println(bigDecimal.divide(bigDecimal2));//可能抛出异常ArithmeticException
                  //在调用divide 方法时,指定精度即可. BigDecimal.ROUND_CEILING
                  //如果有无限循环小数,就会保留 分子 的精度
                  System.out.println(bigDecimal.divide(bigDecimal2, BigDecimal.ROUND_CEILING));
              }
          }
          输出结果:
          1999.11
          2002.11
          1996.11
          5997.33
          666.37
          
        2. biginteger示例

          package com.hspedu.bignum;
          
          import java.math.BigInteger;
          
          public class BigInteger_ {
              public static void main(String[] args) {
          
                  //当我们编程中,需要处理很大的整数,long 不够用
                  //可以使用BigInteger的类来搞定
          //        long l = 23788888899999999999999999999l;
          //        System.out.println("l=" + l);
          
                  BigInteger bigInteger = new BigInteger("23788888899999999999999999999");
                  BigInteger bigInteger2 = new BigInteger("10099999999999999999999999999999999999999999999999999999999999999999999999999999999");
                  System.out.println(bigInteger);
                  //老韩解读
                  //1. 在对 BigInteger 进行加减乘除的时候,需要使用对应的方法,不能直接进行 + - * /
                  //2. 可以创建一个 要操作的 BigInteger 然后进行相应操作
                  BigInteger add = bigInteger.add(bigInteger2);
                  System.out.println(add);//
                  BigInteger subtract = bigInteger.subtract(bigInteger2);
                  System.out.println(subtract);//减
                  BigInteger multiply = bigInteger.multiply(bigInteger2);
                  System.out.println(multiply);//乘
                  BigInteger divide = bigInteger.divide(bigInteger2);
                  System.out.println(divide);//除
          
          
              }
          }
          输出结果:
          23788888899999999999999999999
          10100000000000000000000000000000000000000000000000000023788888899999999999999999998
          -10099999999999999999999999999999999999999999999999999976211111100000000000000000000
          240267777889999999999999999989899999999999999999999999999999999999999999999999999976211111100000000000000000001
          0
          
  4. String类

    1. 介绍
      1. String 对象用于保存字符串,也就是一组字符序列

      2. 字符串常量对象是用双引号括起的字符序列。例如:“你好”、“12.97”、“boy”等

      3. 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节。

      4. String类较常用构造器:

        1. String s1 new String0;//
        2. String s2 new String(String original);
        3. String s3 new String(char[] a);
        4. String s4 new String(char[] a, int startlndex, int count)
    2. 代码示例
      1.  package com.hspedu.string_;
         public class String01 {
             public static void main(String[] args) {
                 //1.String 对象用于保存字符串,也就是一组字符序列
                 //2. "jack" 字符串常量, 双引号括起的字符序列
                 //3. 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
                 //4. String 类有很多构造器,构造器的重载
                 //   常用的有 String  s1 = new String(); //
                 //String  s2 = new String(String original);
                 //String  s3 = new String(char[] a);
                 //String  s4 =  new String(char[] a,int startIndex,int count)
                 //String s5 = new String(byte[] b)
                 //5. String 类实现了接口 Serializable【String 可以串行化:可以在网络传输】
                 //                 接口 Comparable [String 对象可以比较大小]
                 //6. String 是final 类,不能被其他的类继承
                 //7. String 有属性 private final char value[]; 用于存放字符串内容
                 //8. 一定要注意:value 是一个final类型, 不可以修改(需要功力):即value不能指向
                 //   新的地址,但是单个字符内容是可以变化
        
                 String name = "jack";
                 name = "tom";
                 final char[] value = {'a','b','c'};
                 char[] v2 = {'t','o','m'};
                 value[0] = 'H';
                 //value = v2; 不可以修改 value地址
        
             }
         }
         //编译成功
        
    3. 创建对象方式
      1. 方式一:直接赋值 String s=“hspedu”;

      2. 方式二:调用构造器 String s= new String(“hspedu”);

      3. 区别

        1. 方式一:先从常量池查看是否有“hsp”数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址
        2. 方式二:先在堆中创建空间,里面维护了value属性,指向常量池的hsp空间如果常量池没有“hsp”,重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址。
      4. 体系图

      5. 代码示例

        1.  package com.hspedu.string_;
          
           public class StringExercise04 {
               public static void main(String[] args) {
                   String s1 = "hspedu"; //指向常量池”hspedu”
                   String s2 = "java"; //指向常量池”java”
                   String s4 = "java";//指向常量池”java”
                   String s3 = new String("java");//指向堆中对象
                   System.out.println(s2 == s3); // F
                   System.out.println(s2 == s4);  //T
                   System.out.println(s2.equals(s3));//T
                   System.out.println(s1 == s2);  //F
                   System.out.println(s2 == s3.intern());//T
          
               }
           }
          
    4. 常见方法
      1. equals//区分大小写,判断内容是否相等
      2. equalslgnoreCase/忽略大小写的判断内容是否相等 length/获取字符的个数,字符串的长度
      3. indexOf/获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回—1
      4. lastlndexOf/获取字符在字符串中最后1次出现的索引,索引从0开始,如找不到,返回—
      5. 1substring/截取指定范围的子串
      6. trim/去前后空格
      7. charAt:获取某索引处的字符,注意不能使用Str[index]这种方式.
    5. 代码示例
      1.  package com.hspedu.string_;
        
         public class StringMethod01 {
             public static void main(String[] args) {
                 //1. equals 前面已经讲过了. 比较内容是否相同,区分大小写
                 String str1 = "hello";
                 String str2 = "Hello";
                 System.out.println(str1.equals(str2));//
        
                 // 2.equalsIgnoreCase 忽略大小写的判断内容是否相等
                 String username = "johN";
                 if ("john".equalsIgnoreCase(username)) {
                     System.out.println("Success!");
                 } else {
                     System.out.println("Failure!");
                 }
                 // 3.length 获取字符的个数,字符串的长度
                 System.out.println("123".length());
                 // 4.indexOf 获取字符在字符串对象中第一次出现的索引,索引从0开始,如果找不到,返回-1
                 String s1 = "wer@terwe@g";
                 int index = s1.indexOf('@');
                 System.out.println(index);// 3
                 System.out.println("weIndex=" + s1.indexOf("we"));//0
                 // 5.lastIndexOf 获取字符在字符串中最后一次出现的索引,索引从0开始,如果找不到,返回-1
                 s1 = "wer@terwe@g@";
                 index = s1.lastIndexOf('@');
                 System.out.println(index);//11
                 System.out.println("ter的位置=" + s1.lastIndexOf("ter"));//4
                 // 6.substring 截取指定范围的子串
                 String name = "hello,张三";
                 //下面name.substring(6) 从索引6开始截取后面所有的内容
                 System.out.println(name.substring(6));//截取后面的字符
                 //name.substring(0,5)表示从索引0开始截取,截取到索引 5-1=4位置
                 System.out.println(name.substring(2,5));//llo
        
             }
         }
         输出结果:
         false
         Success!
         3
         3
         weIndex=0
         11
         ter的位置=4
         张三
         llo
        
      2.  package com.hspedu.string_;
        
         public class StringMethod02 {
             public static void main(String[] args) {
                 // 1.toUpperCase转换成大写
                 String s = "heLLo";
                 System.out.println(s.toUpperCase());//HELLO
                 // 2.toLowerCase
                 System.out.println(s.toLowerCase());//hello
                 // 3.concat拼接字符串
                 String s1 = "宝玉";
                 s1 = s1.concat("林黛玉").concat("薛宝钗").concat("together");
                 System.out.println(s1);//宝玉林黛玉薛宝钗together
                 // 4.replace 替换字符串中的字符
                 s1 = "宝玉 and 林黛玉 林黛玉 林黛玉";
                 //在s1中,将 所有的 林黛玉 替换成薛宝钗
                 // 老韩解读: s1.replace() 方法执行后,返回的结果才是替换过的.
                 // 注意对 s1没有任何影响
                 String s11 = s1.replace("宝玉", "jack");
                 System.out.println(s1);//宝玉 and 林黛玉 林黛玉 林黛玉
                 System.out.println(s11);//jack and 林黛玉 林黛玉 林黛玉
                 // 5.split 分割字符串, 对于某些分割字符,我们需要 转义比如 | \\等
                 String poem = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";
                 //老韩解读:
                 // 1. 以 , 为标准对 poem 进行分割 , 返回一个数组
                 // 2. 在对字符串进行分割时,如果有特殊字符,需要加入 转义符 \
                 String[] split = poem.split(",");
                 poem = "E:\\aaa\\bbb";
                 split = poem.split("\\\\");
                 System.out.println("==分割后内容===");
                 for (int i = 0; i < split.length; i++) {
                     System.out.println(split[i]);
                 }
                 // 6.toCharArray 转换成字符数组
                 s = "happy";
                 char[] chs = s.toCharArray();
                 for (int i = 0; i < chs.length; i++) {
                     System.out.println(chs[i]);
                 }
                 // 7.compareTo 比较两个字符串的大小,如果前者大,
                 // 则返回正数,后者大,则返回负数,如果相等,返回0
                 // 老韩解读
                 // (1) 如果长度相同,并且每个字符也相同,就返回 0
                 // (2) 如果长度相同或者不相同,但是在进行比较时,可以区分大小
                 //     就返回 if (c1 != c2) {
                 //                return c1 - c2;
                 //            }
                 // (3) 如果前面的部分都相同,就返回 str1.len - str2.len
                 String a = "jcck";// len = 3
                 String b = "jack";// len = 4
                 System.out.println(a.compareTo(b)); // 返回值是 'c' - 'a' = 2的值
         // 8.format 格式字符串
                 /* 占位符有:
                  * %s 字符串 %c 字符 %d 整型 %.2f 浮点型
                  *
                  */
                 String name = "john";
                 int age = 10;
                 double score = 56.857;
                 char gender = '男';
                 //将所有的信息都拼接在一个字符串.
                 String info =
                         "我的姓名是" + name + "年龄是" + age + ",成绩是" + score + "性别是" + gender + "。希望大家喜欢我!";
        
                 System.out.println(info);
        
        
                 //老韩解读
                 //1. %s , %d , %.2f %c 称为占位符
                 //2. 这些占位符由后面变量来替换
                 //3. %s 表示后面由 字符串来替换
                 //4. %d 是整数来替换
                 //5. %.2f 表示使用小数来替换,替换后,只会保留小数点两位, 并且进行四舍五入的处理
                 //6. %c 使用char 类型来替换
                 String formatStr = "我的姓名是%s 年龄是%d,成绩是%.2f 性别是%c.希望大家喜欢我!";
        
                 String info2 = String.format(formatStr, name, age, score, gender);
        
                 System.out.println("info2=" + info2);
             }
         }
         输出结果:
         E:
         aaa
         bbb
         h
         a
         p
         p
         y
         2
         我的姓名是john年龄是10,成绩是56.857性别是男。希望大家喜欢我!
         info2=我的姓名是john 年龄是10,成绩是56.86 性别是男.希望大家喜欢我!
        
  5. StringBuffer类

    1. 介绍
      1. java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删
      2. 很多方法与String相同,但StringBuffer是可变长度的。
      3. StringBuffer是一个容器。
    2. 与string类的区别
      1. String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低/private final char value[];
      2. StringBuffer保存的是字符串变量,里面的值可以更改,每次
        StringBuffer的更新实际上可以更新内容,不用每次更新地址,效率较高/char[]value;/这个放在堆.
    3. string与stringbuffer的转换
      1. 代码示例

        1.  package com.hspedu.stringbuffer_;
          
          
           public class StringAndStringBuffer {
               public static void main(String[] args) {
          
                   //看 String——>StringBuffer
                   String str = "hello tom";
                   //方式1 使用构造器
                   //注意: 返回的才是StringBuffer对象,对str 本身没有影响
                   StringBuffer stringBuffer = new StringBuffer(str);
                   //方式2 使用的是append方法
                   StringBuffer stringBuffer1 = new StringBuffer();
                   stringBuffer1 = stringBuffer1.append(str);
          
                   //看看 StringBuffer ->String
                   StringBuffer stringBuffer3 = new StringBuffer("CongSec教育");
                   //方式1 使用StringBuffer提供的 toString方法
                   String s = stringBuffer3.toString();
                   //方式2: 使用构造器来搞定
                   String s1 = new String(stringBuffer3);
          
               }
           }
           //编译成功
          
    4. 常用方法
      1. append():

        • 用于在StringBuffer对象末尾添加内容
        • 可以连续调用,支持多种数据类型
      2. delete(int start, int end):

        • 删除指定范围内的字符
        • 删除的范围是[start, end),包括start但不包括end
      3. replace(int start, int end, String str):

        • 使用给定的字符串替换指定范围内的字符
        • 替换的范围是[start, end)
      4. indexOf(String str):

        • 查找指定子串第一次出现的索引
        • 如果找不到,返回-1
      5. insert(int offset, String str):

        • 在指定位置插入字符串
        • 原来该位置及之后的内容会自动后移
      6. length():

        • 返回StringBuffer对象的长度
      7. 代码示例

        1.  package com.hspedu.stringbuffer_;
          
           public class StringBufferMethod {
               public static void main(String[] args) {
          
                   StringBuffer s = new StringBuffer("hello");
                   //增
                   s.append(',');// "hello,"
                   s.append("张三丰");//"hello,张三丰"
                   s.append("赵敏").append(100).append(true).append(10.5);//"hello,张三丰赵敏100true10.5"
                   System.out.println(s);//"hello,张三丰赵敏100true10.5"
          
          
                   //删
                   /*
                    * 删除索引为>=start && <end 处的字符
                    * 解读: 删除 11~14的字符 [11, 14)
                    */
                   s.delete(11, 14);
                   System.out.println(s);//"hello,张三丰赵敏true10.5"
                   //改
                   //老韩解读,使用 周芷若 替换 索引9-11的字符 [9,11)
                   s.replace(9, 11, "周芷若");
                   System.out.println(s);//"hello,张三丰周芷若true10.5"
                   //查找指定的子串在字符串第一次出现的索引,如果找不到返回-1
                   int indexOf = s.indexOf("张三丰");
                   System.out.println(indexOf);//6
                   //插
                   //老韩解读,在索引为9的位置插入 "赵敏",原来索引为9的内容自动后移
                   s.insert(9, "赵敏");
                   System.out.println(s);//"hello,张三丰赵敏周芷若true10.5"
                   //长度
                   System.out.println(s.length());//22
                   System.out.println(s);
          
               }
           }
          
  6. ​StringBuilder类

    1. 介绍
      1. 一个可变的字符序列。此类提供一个与StringBuffer 兼容的API,但不保证同步(StringBuilder 不是线程安全)。该类被设计用作 StringBuffer的一个简易 替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类因为在大多数实现中,它比 StringBuffer 要快[后面测]。
      2. 在StringBuilder 上的主要操作是 append 和 insert 方法,可重载这些方法, 以接受任意类型的数据。
    2. 常用方法
      1. StringBuilder 和 StringBuffer 均代表可变的字符序列,方法是一样的,所 以使用和StringBuffer一样,看老师演示.[参考StringBuffer].
      2. StringBuilder 是final
      3. 继承了AbstractStringBuilder, 属性char[] value,内容存到 value
      4. 实现了Serializable接口,序列化 (所谓序列化即可以保存类型和数据本
    3. string,stringbuffer,stringbuilder三者的区别和原则
      1. 区别

        1. StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且方法
          也一样
        2. String:不可变字符序列,效率低,但是复用率高。
        3. StringBuffer:可变字符序列、效率较高(增删)、线程安全,看源码
        4. StringBuilder:可变字符序列、效率最高、线程不安全
        5. String使用注意说明:
          string s=“a”;/创建了一个字符串
          s+=“b”;//实际上原来的“a”字符串对象已经丢弃了,现在又产生了一个字符串s+“b”(也就是“ab”)。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能=>结论:如果我们对String 做大量修改,不要使用String
      2. 原则

        1. 如果字符串存在大量的修改操作,一般使用 StringBuffer 或StringBuilde
        2. 如果字符串存在大量的修改操作,并在单线程的情况,使用StringBuilder
        3. 如果字符串存在大量的修改操作,并在多线程的情况,使用StringBuffer
        4. 如果我们字符串很少修改,被多个对象引用,使用String,比如配置信息等

Math类

  1. 介绍

    1. Math类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数
  2. 常用方法

    1. Math.abs(int a)

      • 功能:求绝对值
    2. Math.pow(double base, double exponent)

      • 功能:求幂
    3. Math.ceil(double a)

      • 功能:向上取整,返回大于或等于参数的最小整数(double类型)
    4. Math.floor(double a)

      • 功能:向下取整,返回小于或等于参数的最大整数(double类型)
    5. Math.round(double a)

      • 功能:四舍五入
    6. Math.sqrt(double a)

      • 功能:求平方根
    7. Math.random()

      • 功能:返回0到1之间的随机小数(包括0,不包括1)
    8. Math.min(int a, int b)

      • 功能:返回两个数中的最小值
    9. Math.max(int a, int b)

      • 功能:返回两个数中的最大值
  3. 代码示例

    1.  package com.hspedu.math_;
      
      
       public class MathMethod {
           public static void main(String[] args) {
               //看看Math常用的方法(静态方法)
               //1.abs 绝对值
               int abs = Math.abs(-9);
               System.out.println(abs);//9
               //2.pow 求幂
               double pow = Math.pow(2, 4);//2的4次方
               System.out.println(pow);//16
               //3.ceil 向上取整,返回>=该参数的最小整数(转成double);
               double ceil = Math.ceil(3.9);
               System.out.println(ceil);//4.0
               //4.floor 向下取整,返回<=该参数的最大整数(转成double)
               double floor = Math.floor(4.001);
               System.out.println(floor);//4.0
               //5.round 四舍五入  Math.floor(该参数+0.5)
               long round = Math.round(5.51);
               System.out.println(round);//6
               //6.sqrt 求开方
               double sqrt = Math.sqrt(9.0);
               System.out.println(sqrt);//3.0
      
               //7.random 求随机数
               //  random 返回的是 0 <= x < 1 之间的一个随机小数
               // 思考:请写出获取 a-b之间的一个随机整数,a,b均为整数 ,比如 a = 2, b=7
               //  即返回一个数 x  2 <= x <= 7
               // 老韩解读 Math.random() * (b-a) 返回的就是 0  <= 数 <= b-a
               // (1) (int)(a) <= x <= (int)(a + Math.random() * (b-a +1) )
               // (2) 使用具体的数给小伙伴介绍 a = 2  b = 7
               //  (int)(a + Math.random() * (b-a +1) ) = (int)( 2 + Math.random()*6)
               //  Math.random()*6 返回的是 0 <= x < 6 小数
               //  2 + Math.random()*6 返回的就是 2<= x < 8 小数
               //  (int)(2 + Math.random()*6) = 2 <= x <= 7
               // (3) 公式就是  (int)(a + Math.random() * (b-a +1) )
               for(int i = 0; i < 100; i++) {
                   System.out.println((int)(2 +  Math.random() * (7 - 2 + 1)));
               }
      
               //max , min 返回最大值和最小值
               int min = Math.min(1, 9);
               int max = Math.max(45, 90);
               System.out.println("min=" + min);
               System.out.println("max=" + max);
      
           }
       }
       输出结果:
       9
       16.0
       4.0
       4.0
       6
       3.0
       3
       6
       6
       7
       4
       4
       5
       5
       3
       4
       4
       3
       3
       4
       4
       3
       3
       3
       4
       7
       6
       3
       2
       6
       4
       2
       3
       3
       4
       7
       5
       6
       3
       6
       7
       6
       7
       4
       2
       3
       2
       4
       7
       5
       5
       3
       3
       5
       6
       5
       6
       4
       2
       3
       5
       6
       7
       5
       4
       7
       2
       3
       5
       6
       3
       4
       7
       6
       7
       5
       3
       3
       3
       5
       5
       3
       6
       4
       2
       6
       4
       6
       2
       6
       2
       3
       5
       7
       5
       7
       2
       3
       5
       3
       2
       4
       2
       4
       5
       4
       min=1
       max=90
      

Arrays类

  1. 常用方法

    1. toString 返回数组的字符串形式
    2. sort 排序(自然排序和定制排序)
    3. binarySearch 通过二分搜索法进行查找,要求必须排好序
    4. copyOf 数组元素的复制
    5. fill 数组元素的填充
    6. equals 比较两个数组元素内容是否完全一致
    7. asList 将一组值,转换成list
  2. 代码示例

    1.  package com.hspedu.arrays_;
      
       import java.util.Arrays;
       import java.util.List;
      
       public class ArraysMethod02 {
           public static void main(String[] args) {
               Integer[] arr = {1, 2, 90, 123, 567};
               System.out.println(Arrays.toString(arr));
               // binarySearch 通过二分搜索法进行查找,要求必须排好
               // 解读
               //1. 使用 binarySearch 二叉查找
               //2. 要求该数组是有序的. 如果该数组是无序的,不能使用binarySearch
               //3. 如果数组中不存在该元素,就返回 return -(low + 1);  // key not found.
               int index = Arrays.binarySearch(arr, 567);
               System.out.println("index=" + index);
      
               //copyOf 数组元素的复制
               // 解读
               //1. 从 arr 数组中,拷贝 arr.length个元素到 newArr数组中
               //2. 如果拷贝的长度 > arr.length 就在新数组的后面 增加 null
               //3. 如果拷贝长度 < 0 就抛出异常NegativeArraySizeException
               //4. 该方法的底层使用的是 System.arraycopy()
               Integer[] newArr = Arrays.copyOf(arr, arr.length);
               System.out.println("==拷贝执行完毕后==");
               System.out.println(Arrays.toString(newArr));
      
               //ill 数组元素的填充
               Integer[] num = new Integer[]{9,3,2};
               //解读
               //1. 使用 99 去填充 num数组,可以理解成是替换原理的元素
               Arrays.fill(num, 99);
               System.out.println("==num数组填充后==");
               System.out.println(Arrays.toString(num));
      
               //equals 比较两个数组元素内容是否完全一致
               Integer[] arr2 = {1, 2, 90, 123};
               //解读
               //1. 如果arr 和 arr2 数组的元素一样,则方法true;
               //2. 如果不是完全一样,就返回 false
               boolean equals = Arrays.equals(arr, arr2);
               System.out.println("equals=" + equals);
      
               //asList 将一组值,转换成list
               //解读
               //1. asList方法,会将 (2,3,4,5,6,1)数据转成一个List集合
               //2. 返回的 asList 编译类型 List(接口)
               //3. asList 运行类型 java.util.Arrays#ArrayList, 是Arrays类的
               //   静态内部类 private static class ArrayList<E> extends AbstractList<E>
               //              implements RandomAccess, java.io.Serializable
               List asList = Arrays.asList(2,3,4,5,6,1);
               System.out.println("asList=" + asList);
               System.out.println("asList的运行类型" + asList.getClass());
      
      
      
           }
       }
       输出结果:
       [1, 2, 90, 123, 567]
       index=4
       ==拷贝执行完毕后==
       [1, 2, 90, 123, 567]
       ==num数组填充后==
       [99, 99, 99]
       equals=false
       asList=[2, 3, 4, 5, 6, 1]
       asList的运行类型class java.util.Arrays$ArrayList
      

System类

  1. 常用方法
    1. exit 退出当前程序
    2. arraycopy: 复制数组元素,比较适合底层调用,一般使用Arrays.copyOf完成复制数组.
    3. currentTimeMillens: 返回当前时间距离1970-1-1的毫秒数
    4. gc: 运行垃圾回收机制System.gc();
  2. 代码示例
    1.  package com.hspedu.system_;
      
       import java.util.Arrays;
      
       public class System_ {
           public static void main(String[] args) {
      
               //exit 退出当前程序
      
       //        System.out.println("ok1");
       //        //解读
       //        //1. exit(0) 表示程序退出
       //        //2. 0 表示一个状态 , 正常的状态
       //        System.exit(0);//
       //        System.out.println("ok2");
      
               //arraycopy :复制数组元素,比较适合底层调用,
               // 一般使用Arrays.copyOf完成复制数组
      
               int[] src={1,2,3};
               int[] dest = new int[3];// dest 当前是 {0,0,0}
      
               //解读
               //1. 主要是搞清楚这五个参数的含义
               //2.
               //     源数组
               //     * @param      src      the source array.
               //     srcPos: 从源数组的哪个索引位置开始拷贝
               //     * @param      srcPos   starting position in the source array.
               //     dest : 目标数组,即把源数组的数据拷贝到哪个数组
               //     * @param      dest     the destination array.
               //     destPos: 把源数组的数据拷贝到 目标数组的哪个索引
               //     * @param      destPos  starting position in the destination data.
               //     length: 从源数组拷贝多少个数据到目标数组
               //     * @param      length   the number of array elements to be copied.
               System.arraycopy(src, 0, dest, 0, src.length);
               // int[] src={1,2,3};
               System.out.println("dest=" + Arrays.toString(dest));//[1, 2, 3]
      
               //currentTimeMillens:返回当前时间距离1970-1-1 的毫秒数
               // 解读:
               System.out.println(System.currentTimeMillis());
      
      
           }
       }
       //dest=[1, 2, 3]
       //1728893605219
      

日期类

  1. 第一代日期类–Date

    1. 介绍
      1. Date:精确到毫秒,代表特定的瞬间,类是在java.util包
      2. SimpleDateFormat:格式和解析日期的类 SimpleDateFormat格式化和解析日期的具 体类。它允许进行格式化(日期—>文本)、解析(文本—>日期)和规范化.
    2. 代码示例
      1.  package com.hspedu.date_;
        
         import java.text.ParseException;
         import java.text.SimpleDateFormat;
         import java.util.Date;
        
        
         public class Date01 {
             public static void main(String[] args) throws ParseException {
        
                 //解读
                 //1. 获取当前系统时间
                 //2. 这里的Date 类是在java.util包
                 //3. 默认输出的日期格式是国外的方式, 因此通常需要对格式进行转换
                 Date d1 = new Date(); //获取当前系统时间
                 System.out.println("当前日期=" + d1);
                 Date d2 = new Date(9234567); //通过指定毫秒数得到时间
                 System.out.println("d2=" + d2); //获取某个时间对应的毫秒数
         //
        
                 //解读
                 //1. 创建 SimpleDateFormat对象,可以指定相应的格式
                 //2. 这里的格式使用的字母是规定好,不能乱写
        
                 SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
                 String format = sdf.format(d1); // format:将日期转换成指定格式的字符串
                 System.out.println("当前日期=" + format);
        
                 //解读
                 //1. 可以把一个格式化的String 转成对应的 Date
                 //2. 得到Date 仍然在输出时,还是按照国外的形式,如果希望指定格式输出,需要转换
                 //3. 在把String -> Date , 使用的 sdf 格式需要和你给的String的格式一样,否则会抛出转换异常
                 String s = "1996年01月01日 10:20:30 星期一";
                 Date parse = sdf.parse(s);
                 System.out.println("parse=" + sdf.format(parse));
        
             }
         }
         输出结果:
         当前日期=Mon Oct 14 16:31:15 CST 2024
         d2=Thu Jan 01 10:33:54 CST 1970
         当前日期=2024101404:31:15 星期一
         parse=1996010110:20:30 星期一
        
  2. 第二代日期类–Calendar

    1. 介绍
      1. 第二代日期类,主要就是 Calendar类(日历)。
        public abstract class Calendar extends Object implements Serializable,
        Cloneable, Comparable
      2. Calendar类是一个抽象类,它为特定瞬间与一组诸如YEAR、MONTH、DAY_OFMONTH、HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。
    2. 代码示例
      1.  package com.hspedu.date_;
        
         import java.util.Calendar;
        
         public class Calendar_ {
             public static void main(String[] args) {
                 //解读
                 //1. Calendar是一个抽象类, 并且构造器是private
                 //2. 可以通过 getInstance() 来获取实例
                 //3. 提供大量的方法和字段提供给程序员
                 //4. Calendar没有提供对应的格式化的类,因此需要程序员自己组合来输出(灵活)
                 //5. 如果我们需要按照 24小时进制来获取时间, Calendar.HOUR ==改成=> Calendar.HOUR_OF_DAY
                 Calendar c = Calendar.getInstance(); //创建日历类对象//比较简单,自由
                 System.out.println("c=" + c);
                 //2.获取日历对象的某个日历字段
                 System.out.println("年:" + c.get(Calendar.YEAR));
                 // 这里为什么要 + 1, 因为Calendar 返回月时候,是按照 0 开始编号
                 System.out.println("月:" + (c.get(Calendar.MONTH) + 1));
                 System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH));
                 System.out.println("小时:" + c.get(Calendar.HOUR));
                 System.out.println("分钟:" + c.get(Calendar.MINUTE));
                 System.out.println("秒:" + c.get(Calendar.SECOND));
                 //Calender 没有专门的格式化方法,所以需要程序员自己来组合显示
                 System.out.println(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" + c.get(Calendar.DAY_OF_MONTH) +
                         " " + c.get(Calendar.HOUR_OF_DAY) + ":" + c.get(Calendar.MINUTE) + ":" + c.get(Calendar.SECOND) );
        
             }
         }
         输出结果:
         c=java.util.GregorianCalendar[time=1728895290907,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=31,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2024,MONTH=9,WEEK_OF_YEAR=42,WEEK_OF_MONTH=3,DAY_OF_MONTH=14,DAY_OF_YEAR=288,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=4,HOUR_OF_DAY=16,MINUTE=41,SECOND=30,MILLISECOND=907,ZONE_OFFSET=28800000,DST_OFFSET=0]
         年:2024
         月:10
         日:14
         小时:4
         分钟:41
         秒:30
         2024-10-14 16:41:30
        
  3. 第三代日期类

    1. 基本使用
      1. 代码示例

        1.  package com.hspedu.date_;
          
           import java.time.Instant;
           import java.time.LocalDate;
           import java.time.LocalDateTime;
           import java.time.LocalTime;
           import java.time.format.DateTimeFormatter;
           import java.util.ArrayList;
           import java.util.Collection;
          
           public class LocalDate_ {
               public static void main(String[] args) {
                   //第三代日期
                   //解读
                   //1. 使用now() 返回表示当前日期时间的 对象
                   LocalDateTime ldt = LocalDateTime.now(); //LocalDate.now();//LocalTime.now()
                   System.out.println(ldt);
          
                   //2. 使用DateTimeFormatter 对象来进行格式化
                   // 创建 DateTimeFormatter对象
                   DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                   String format = dateTimeFormatter.format(ldt);
                   System.out.println("格式化的日期=" + format);
          
                   System.out.println("年=" + ldt.getYear());
                   System.out.println("月=" + ldt.getMonth());
                   System.out.println("月=" + ldt.getMonthValue());
                   System.out.println("日=" + ldt.getDayOfMonth());
                   System.out.println("时=" + ldt.getHour());
                   System.out.println("分=" + ldt.getMinute());
                   System.out.println("秒=" + ldt.getSecond());
          
                   LocalDate now = LocalDate.now(); //可以获取年月日
                   LocalTime now2 = LocalTime.now();//获取到时分秒
          
          
                   //提供 plus 和 minus方法可以对当前时间进行加或者减
                   //看看890天后,是什么时候 把 年月日-时分秒
                   LocalDateTime localDateTime = ldt.plusDays(890);
                   System.out.println("890天后=" + dateTimeFormatter.format(localDateTime));
          
                   //看看在 3456分钟前是什么时候,把 年月日-时分秒输出
                   LocalDateTime localDateTime2 = ldt.minusMinutes(3456);
                   System.out.println("3456分钟前 日期=" + dateTimeFormatter.format(localDateTime2));
          
               }
           }
           输出结果:
           2024-10-14T17:14:56.487
           格式化的日期=2024-10-14 17:14:56=2024=OCTOBER
           月=10=14=17=14=56
           890天后=2027-03-23 17:14:56
           3456分钟前 日期=2024-10-12 07:38:56
          
    2. instant时间戳
      1.  package com.hspedu.date_;
        
         import java.time.Instant;
         import java.util.Date;
        
         public class Instant_ {
             public static void main(String[] args) {
        
                 //1.通过 静态方法 now() 获取表示当前时间戳的对象
                 Instant now = Instant.now();
                 System.out.println(now);
                 //2. 通过 from 可以把 Instant转成 Date
                 Date date = Date.from(now);
                 //3. 通过 date的toInstant() 可以把 date 转成Instant对象
                 Instant instant = date.toInstant();
        
             }
         }
         //2024-10-14T09:28:02.798Z
        

集合

  1. 介绍

    1. 可以动态保存任意多个对象,使用比较方便!
    2. 提供了一系列方便的操作对象的方法:add、remove、set、get等
    3. 使用集合添加,删除新元素的示意代码—简洁了
  2. 框架体系图

  3. Collection的常用接口和方法

    1. Collection的接口的特点
      1. collection实现子类可以存放多个元素,每个元素可以是Object
      2. 有些Collection的实现类,可以存放重复的元素,有些不可以
      3. 有些Collection的实现类,有些是有序的(List),有些不是有序(Set)
      4. Collection接口没有直接的实现子类,是通过它的子接口Set和List来
        实现的
    2. 常用方法
      1. add(Object element)​: 添加单个元素到集合中

      2. remove(Object element)​: 从集合中删除指定元素

      3. contains(Object element)​: 检查集合是否包含指定元素

      4. size()​: 获取集合中元素的数量

      5. isEmpty()​: 检查集合是否为空

      6. clear()​: 清空集合中的所有元素

      7. addAll(Collection c)​: 将另一个集合中的所有元素添加到当前集合

      8. containsAll(Collection c)​: 检查当前集合是否包含另一个集合的所有元素

      9. removeAll(Collection c)​: 从当前集合中删除另一个集合中存在的所有元素

      10. 代码示例
        1.  package com.hspedu.collection_;
          
           import java.util.ArrayList;
           import java.util.List;
          
           public class CollectionMethod {
               @SuppressWarnings({"all"})
               public static void main(String[] args) {
                   List list = new ArrayList();
           //        add:添加单个元素
                   list.add("jack");
                   list.add(10);//list.add(new Integer(10))
                   list.add(true);
                   System.out.println("list=" + list);
           //        remove:删除指定元素
                   //list.remove(0);//删除第一个元素
                   list.remove(true);//指定删除某个元素
                   System.out.println("list=" + list);
           //        contains:查找元素是否存在
                   System.out.println(list.contains("jack"));//T
           //        size:获取元素个数
                   System.out.println(list.size());//2
           //        isEmpty:判断是否为空
                   System.out.println(list.isEmpty());//F
           //        clear:清空
                   list.clear();
                   System.out.println("list=" + list);
           //        addAll:添加多个元素
                   ArrayList list2 = new ArrayList();
                   list2.add("红楼梦");
                   list2.add("三国演义");
                   list.addAll(list2);
                   System.out.println("list=" + list);
           //        containsAll:查找多个元素是否都存在
                   System.out.println(list.containsAll(list2));//T
           //        removeAll:删除多个元素
                   list.add("聊斋");
                   list.removeAll(list2);
                   System.out.println("list=" + list);//[聊斋]
           //        说明:以ArrayList实现类来演示.
          
               }
           }
           输出结果:
           list=[jack, 10, true]
           list=[jack, 10]
           true
           2
           false
           list=[]
           list=[红楼梦, 三国演义]
           true
           list=[聊斋]
          
    3. 接口遍历元素方式1–使用Iterator(迭代器)
      1. 介绍
        1. Iterator对象称为迭代器,主要用于遍历 Collection集合中的元素。
        2. 所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了lterator接口的对象,即可以返回一个迭代器。
        3. Iterator 的结构.[看一张图]
        4. Iterator 仅用于遍历集合,Iterator 本身并不存放对象。
      2. 代码示例
        1.  package com.hspedu.collection_;
          
          
           import java.util.ArrayList;
           import java.util.Collection;
           import java.util.Iterator;
          
           public class CollectionIterator {
               @SuppressWarnings({"all"})
               public static void main(String[] args) {
          
                   Collection col = new ArrayList();
          
                   col.add(new Book("三国演义", "罗贯中", 10.1));
                   col.add(new Book("小李飞刀", "古龙", 5.1));
                   col.add(new Book("红楼梦", "曹雪芹", 34.6));
          
          
                   //System.out.println("col=" + col);
                   //现在老师希望能够遍历 col集合
                   //1. 先得到 col 对应的 迭代器
                   Iterator iterator = col.iterator();
                   //2. 使用while循环遍历
           //        while (iterator.hasNext()) {//判断是否还有数据
           //            //返回下一个元素,类型是Object
           //            Object obj = iterator.next();
           //            System.out.println("obj=" + obj);
           //        }
                   //老师教大家一个快捷键,快速生成 while => itit
                   //显示所有的快捷键的的快捷键 ctrl + j
                   while (iterator.hasNext()) {
                       Object obj = iterator.next();
                       System.out.println("obj=" + obj);
          
                   }
                   //3. 当退出while循环后 , 这时iterator迭代器,指向最后的元素
                   //   iterator.next();//NoSuchElementException
                   //4. 如果希望再次遍历,需要重置我们的迭代器
                   iterator = col.iterator();
                   System.out.println("===第二次遍历===");
                   while (iterator.hasNext()) {
                       Object obj = iterator.next();
                       System.out.println("obj=" + obj);
          
                   }
          
               }
           }
          
           class Book {
               private String name;
               private String author;
               private double price;
          
               public Book(String name, String author, double price) {
                   this.name = name;
                   this.author = author;
                   this.price = price;
               }
          
               public String getName() {
                   return name;
               }
          
               public void setName(String name) {
                   this.name = name;
               }
          
               public String getAuthor() {
                   return author;
               }
          
               public void setAuthor(String author) {
                   this.author = author;
               }
          
               public double getPrice() {
                   return price;
               }
          
               public void setPrice(double price) {
                   this.price = price;
               }
          
               @Override
               public String toString() {
                   return "Book{" +
                           "name='" + name + '\'' +
                           ", author='" + author + '\'' +
                           ", price=" + price +
                           '}';
               }
           }
           输出结果:
           obj=Book{name='三国演义', author='罗贯中', price=10.1}
           obj=Book{name='小李飞刀', author='古龙', price=5.1}
           obj=Book{name='红楼梦', author='曹雪芹', price=34.6}
           ===第二次遍历===
           obj=Book{name='三国演义', author='罗贯中', price=10.1}
           obj=Book{name='小李飞刀', author='古龙', price=5.1}
           obj=Book{name='红楼梦', author='曹雪芹', price=34.6}
          
    4. 接口遍历元素方式2–for循环增强
      1. 介绍
        1. 增强for循环,可以代替iterator迭代器
      2. 特点
        1. 增强for就是简化版的iterator, 本质一样。只能用于遍历集合或数组。
      3. 基本语法
        1. for(元素类型 元素名 : 集合名或数组名){
          访问元素
          }
      4. 代码示例
        1. 1.创建3个Dog {name,age}对象,放入到 ArrayList中,赋给 List引用
          2.用迭代器和增强for循环两种方式来遍历
          3.重写Dog 的toString方法,输出name和age

          1.  package com.hspedu.collection_;
            
             import java.util.ArrayList;
             import java.util.Iterator;
             import java.util.List;
            
             public class CollectionExercise {
                 @SuppressWarnings({"all"})
                 public static void main(String[] args) {
                     List list = new ArrayList();
                     list.add(new Dog("小黑", 3));
                     list.add(new Dog("大黄", 100));
                     list.add(new Dog("大壮", 8));
            
            
                     //先使用for增强
                     for (Object dog : list) {
                         System.out.println("dog=" + dog);
                     }
            
                     //使用迭代器
                     System.out.println("===使用迭代器来遍历===");
                     Iterator iterator = list.iterator();
                     while (iterator.hasNext()) {
                         Object dog =  iterator.next();
                         System.out.println("dog=" + dog);
            
                     }
            
                 }
             }
             /**
              * 创建  3个 Dog {name, age}  对象,放入到 ArrayList 中,赋给 List 引用
              * 用迭代器和增强for循环两种方式来遍历
              * 重写Dog 的toString方法, 输出name和age
              */
             class Dog {
                 private String name;
                 private int age;
            
                 public Dog(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 "Dog{" +
                             "name='" + name + '\'' +
                             ", age=" + age +
                             '}';
                 }
             }
             输出结果:
             dog=Dog{name='小黑', age=3}
             dog=Dog{name='大黄', age=100}
             dog=Dog{name='大壮', age=8}
             ===使用迭代器来遍历===
             dog=Dog{name='小黑', age=3}
             dog=Dog{name='大黄', age=100}
             dog=Dog{name='大壮', age=8}
            
  4. List接口和常用方法

    1. 介绍
      1. List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复
      2. List集合中的每个元素都有其对应的顺序索引,即支持索引。
      3. List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
    2. 常用方法
       * ​`add(Object ele)`​: 在列表末尾添加元素
       * ​`add(int index, Object ele)`​: 在指定索引位置插入元素
       * ​`addAll(int index, Collection eles)`​: 从指定索引位置开始,添加另一个集合的所有元素
       * ​`get(int index)`​: 获取指定索引位置的元素(示例中提到但未展示)
       * ​`indexOf(Object obj)`​: 返回指定元素在列表中第一次出现的索引
       * ​`lastIndexOf(Object obj)`​: 返回指定元素在列表中最后一次出现的索引
       * ​`remove(int index)`​: 移除指定索引位置的元素,并返回该元素
       * ​`set(int index, Object ele)`​: 将指定索引位置的元素替换为新元素
       * ​`subList(int fromIndex, int toIndex)`​: 返回列表中指定范围的子列表(包含 fromIndex,不包含 toIndex)
       * ###### 代码示例
      
         * ```java
           package com.hspedu.list_;
      
           import java.util.ArrayList;
           import java.util.List;
      
           public class ListMethod {
               @SuppressWarnings({"all"})
               public static void main(String[] args) {
                   List list = new ArrayList();
                   list.add("张三丰");
                   list.add("贾宝玉");
           //        void add(int index, Object ele):在index位置插入ele元素
                   //在index = 1的位置插入一个对象
                   list.add(1, "韩顺平");
                   System.out.println("list=" + list);
           //        boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
                   List list2 = new ArrayList();
                   list2.add("jack");
                   list2.add("tom");
                   list.addAll(1, list2);
                   System.out.println("list=" + list);
           //        Object get(int index):获取指定index位置的元素
                   //说过
           //        int indexOf(Object obj):返回obj在集合中首次出现的位置
                   System.out.println(list.indexOf("tom"));//2
           //        int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
                   list.add("韩顺平");
                   System.out.println("list=" + list);
                   System.out.println(list.lastIndexOf("韩顺平"));
           //        Object remove(int index):移除指定index位置的元素,并返回此元素
                   list.remove(0);
                   System.out.println("list=" + list);
           //        Object set(int index, Object ele):设置指定index位置的元素为ele , 相当于是替换.
                   list.set(1, "玛丽");
                   System.out.println("list=" + list);
           //        List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
                   // 注意返回的子集合 fromIndex <= subList < toIndex
                   List returnlist = list.subList(0, 2);
                   System.out.println("returnlist=" + returnlist);
      
               }
           }
           输出结果:
           list=[张三丰, 韩顺平, 贾宝玉]
           list=[张三丰, jack, tom, 韩顺平, 贾宝玉]
           2
           list=[张三丰, jack, tom, 韩顺平, 贾宝玉, 韩顺平]
           5
           list=[jack, tom, 韩顺平, 贾宝玉, 韩顺平]
           list=[jack, 玛丽, 韩顺平, 贾宝玉, 韩顺平]
           returnlist=[jack, 玛丽]
           ```
      
    3. 三种遍历方式[ArrayList,LinkedList,Vector]
      1. 代码示例
        1.  package com.hspedu.list_;
          
           import java.util.*;
          
          
           public class ListFor {
               @SuppressWarnings({"all"})
               public static void main(String[] args) {
          
                   //List 接口的实现子类 Vector LinkedList
                   //List list = new ArrayList();
                   //List list = new Vector();
                   List list = new LinkedList();
          
                   list.add("jack");
                   list.add("tom");
                   list.add("鱼香肉丝");
                   list.add("北京烤鸭子");
          
                   //遍历
                   //1. 迭代器
                   Iterator iterator = list.iterator();
                   while (iterator.hasNext()) {
                       Object obj =  iterator.next();
                       System.out.println(obj);
          
                   }
          
                   System.out.println("=====增强for=====");
                   //2. 增强for
                   for (Object o : list) {
                       System.out.println("o=" + o);
                   }
          
                   System.out.println("=====普通for====");
                   //3. 使用普通for
                   for (int i = 0; i < list.size(); i++) {
                       System.out.println("对象=" + list.get(i));
                   }
          
          
               }
           }
           输出结果:
           jack
           tom
           鱼香肉丝
           北京烤鸭子
           =====增强for=====
           o=jack
           o=tom
           o=鱼香肉丝
           o=北京烤鸭子
           =====普通for====
           对象=jack
           对象=tom
           对象=鱼香肉丝
           对象=北京烤鸭子
          
    4. 代码示例
        1.  package com.hspedu.list_;
          
           import java.util.ArrayList;
           import java.util.LinkedList;
           import java.util.List;
           import java.util.Vector;
          
           @SuppressWarnings({"all"})
           public class ListExercise02 {
          
               public static void main(String[] args) {
          
                   //List list = new ArrayList();
                   List list = new LinkedList();
                   //List list = new Vector();
                   list.add(new Book("红楼梦", "曹雪芹", 100));
                   list.add(new Book("西游记", "吴承恩", 10));
                   list.add(new Book("水浒传", "施耐庵", 19));
                   list.add(new Book("三国", "罗贯中", 80));
                   //list.add(new Book("西游记", "吴承恩", 10));
          
                   //如何对集合进行排序
          
          
                   //遍历
          
                   for (Object o : list) {
                       System.out.println(o);
                   }
          
                   //冒泡排序
                   sort(list);
          
                   System.out.println("==排序后==");
          
                   for (Object o : list) {
                       System.out.println(o);
                   }
          
               }
          
               //静态方法
               //价格要求是从小到大
               public static void sort(List list) {
          
                   int listSize = list.size();
                   for (int i = 0; i < listSize - 1; i++) {
                       for (int j = 0; j < listSize - 1 - i; j++) {
                           //取出对象Book
                           Book book1 = (Book) list.get(j);
                           Book book2 = (Book) list.get(j + 1);
                           if (book1.getPrice() > book2.getPrice()) {//交换
                               list.set(j, book2);
                               list.set(j + 1, book1);
                           }
                       }
                   }
          
               }
           }
           输出结果:
           名称:红楼梦		价格:100.0		作者:曹雪芹
           名称:西游记		价格:10.0		作者:吴承恩
           名称:水浒传		价格:19.0		作者:施耐庵
           名称:三国		价格:80.0		作者:罗贯中
           ==排序后==
           名称:西游记		价格:10.0		作者:吴承恩
           名称:水浒传		价格:19.0		作者:施耐庵
           名称:三国		价格:80.0		作者:罗贯中
           名称:红楼梦		价格:100.0		作者:曹雪芹
          
  5. 各节点的底层架构和原理跳过(516)

泛型

  1. 介绍

    1. 理解:泛(广泛)型(类型)=>Integer, String,Dog
      1)泛型又称参数化类型,是Jdk5.0出现的新特性,解决数据类型的安全性问题2)在类声明或实例化时只要指定好需要的具体的类型即可。
      3)Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮
      4)泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型。[有点难,举例Generic03.java]
  2. 代码示例

    1.  package com.hspedu.generic;
      
       import java.util.List;
      
       public class Generic03 {
           public static void main(String[] args) {
      
               //注意,特别强调: E具体的数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
               Person<String> person = new Person<String>("韩顺平教育");
               person.show(); //String
      
               /*
                   你可以这样理解,上面的Person类
                   class Person {
                       String s ;//E表示 s的数据类型, 该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
      
                       public Person(String s) {//E也可以是参数类型
                           this.s = s;
                       }
      
                       public String f() {//返回类型使用E
                           return s;
                       }
                   }
                */
      
               Person<Integer> person2 = new Person<Integer>(100);
               person2.show();//Integer
      
               /*
                   class Person {
                       Integer s ;//E表示 s的数据类型, 该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
      
                       public Person(Integer s) {//E也可以是参数类型
                           this.s = s;
                       }
      
                       public Integer f() {//返回类型使用E
                           return s;
                       }
                   }
                */
           }
       }
      
       //泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,
       // 或者是某个方法的返回值的类型,或者是参数类型
      
       class Person<E> {
           E s ;//E表示 s的数据类型, 该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
      
           public Person(E s) {//E也可以是参数类型
               this.s = s;
           }
      
           public E f() {//返回类型使用E
               return s;
           }
      
           public void show() {
               System.out.println(s.getClass());//显示s的运行类型
           }
       }
       //class java.lang.String
       //class java.lang.Integer
      
  3. 语法

    1. 声明
      1. interface 接口 {}和class 类 <K,V>{}

        1. 说明:

          1. 其中,T,K,V不代表任何值,而是表示类型
          2. 任意字母都可以,常用T表示,是Type的缩写
    2. 实例化
      1. 要在类名后面执行类型参数的值(类型),如:

        1. List dtrList = new ArrayList ();
        2. Iterator iterator = customers.iterator();
  4. 代码示例

    1.  package com.hspedu.generic;
      
       import java.util.*;
      
       @SuppressWarnings({"all"})
       public class GenericExercise {
           public static void main(String[] args) {
               //使用泛型方式给HashSet 放入3个学生对象
               HashSet<Student> students = new HashSet<Student>();
               students.add(new Student("jack", 18));
               students.add(new Student("tom", 28));
               students.add(new Student("mary", 19));
      
               //遍历
               for (Student student : students) {
                   System.out.println(student);
               }
      
               //使用泛型方式给HashMap 放入3个学生对象
               //K -> String V->Student
               HashMap<String, Student> hm = new HashMap<String, Student>();
               /*
                   public class HashMap<K,V>  {}
                */
               hm.put("milan", new Student("milan", 38));
               hm.put("smith", new Student("smith", 48));
               hm.put("hsp", new Student("hsp", 28));
      
               //迭代器 EntrySet
               /*
               public Set<Map.Entry<K,V>> entrySet() {
                   Set<Map.Entry<K,V>> es;
                   return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
               }
                */
               Set<Map.Entry<String, Student>> entries = hm.entrySet();
               /*
                   public final Iterator<Map.Entry<K,V>> iterator() {
                       return new EntryIterator();
                   }
                */
               Iterator<Map.Entry<String, Student>> iterator = entries.iterator();
               System.out.println("==============================");
               while (iterator.hasNext()) {
                   Map.Entry<String, Student> next =  iterator.next();
                   System.out.println(next.getKey() + "-" + next.getValue());
           
               }
      
           }
       }
       /**
        * 创建  3个学生对象
        * 放入到HashSet中学生对象, 使用.
        * 放入到  HashMap中,要求 Key 是 String name, Value 就是 学生对象
        * 使用两种方式遍历
        */
       class Student {
           private String name;
           private int age;
      
           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 +
                       '}';
           }
       }
       输出结果:
       Student{name='tom', age=28}
       Student{name='jack', age=18}
       Student{name='mary', age=19}
       ==============================
       smith-Student{name='smith', age=48}
       hsp-Student{name='hsp', age=28}
       milan-Student{name='milan', age=38}
      
  5. 使用细节

    1. interface List{},public class HashSet{}.等等 说明:T,E只能是引用类型
      看看下面语句是否正确?:
      List list new ArrayList0; //OK
      List list2 = new ArrayList();//错误

    2. 在给泛型指定具体类型后,可以传入该类型或者其子类类型

    3. 泛型使用形式
      List list1 new ArrayList(); List list2 = new ArrayList<>();[说明:]

    4. 如果我们这样写List list3=new ArrayList();默认给它的泛型是[E就是Object] 即:

    5. 代码示例
      1.  package com.hspedu.generic;
        
         import java.util.ArrayList;
         import java.util.List;
        
        
         @SuppressWarnings({"all"})
         public class GenericDetail {
             public static void main(String[] args) {
                 //1.给泛型指向数据类型是,要求是引用类型,不能是基本数据类型
                 List<Integer> list = new ArrayList<Integer>(); //OK
                 //List<int> list2 = new ArrayList<int>();//错误
        
                 //2. 说明
                 //因为 E 指定了 A 类型, 构造器传入了 new A()
                 //在给泛型指定具体类型后,可以传入该类型或者其子类类型
                 Pig<A> aPig = new Pig<A>(new A());
                 aPig.f();
                 Pig<A> aPig2 = new Pig<A>(new B());
                 aPig2.f();
        
                 //3. 泛型的使用形式
                 ArrayList<Integer> list1 = new ArrayList<Integer>();
                 List<Integer> list2 = new ArrayList<Integer>();
                 //在实际开发中,我们往往简写
                 //编译器会进行类型推断, 老师推荐使用下面写法
                 ArrayList<Integer> list3 = new ArrayList<>();
                 List<Integer> list4 = new ArrayList<>();
                 ArrayList<Pig> pigs = new ArrayList<>();
        
                 //4. 如果是这样写 泛型默认是 Object
                 ArrayList arrayList = new ArrayList();//等价 ArrayList<Object> arrayList = new ArrayList<Object>();
        
                 /*
                     public boolean add(Object e) {
                         ensureCapacityInternal(size + 1);  // Increments modCount!!
                         elementData[size++] = e;
                         return true;
                     }
                  */
                 Tiger tiger = new Tiger();
                 /*
        
                     class Tiger {//类
                         Object e;
        
                         public Tiger() {}
        
                         public Tiger(Object e) {
                             this.e = e;
                         }
                     }
        
                  */
        
             }
         }
         class Tiger<E> {//类
             E e;
        
             public Tiger() {}
        
             public Tiger(E e) {
                 this.e = e;
             }
         }
        
         class A {}
         class B extends A {}
        
         class Pig<E> {//
             E e;
        
             public Pig(E e) {
                 this.e = e;
             }
        
             public void f() {
                 System.out.println(e.getClass()); //运行类型
             }
         }
         //class com.hspedu.generic.A
         //class com.hspedu.generic.B
        
  6. 代码示例*

    1. 要求:
      定义Employee类
      1)该类包含:private成员变量name,sal,birthday,其中 birthday 为 MyDate类的对 象;
      2)为每一个属性定义getter, setter 方法; 3)重写toString 方法输出 name, sal, birthday
      4)MyDate类包含:private成员变量month,day,year;并为每一个属性定义 getter, setter 方法;
      5)创建该类的3个对象,并把这些对象放入ArrayList 集合中(ArrayList 需使用泛型来定义),对集合中的元素进行排序,并遍历输出:
      排序方式:调用ArrayList的sort方法,传入Comparator对象[使用泛型],先按照 name排序,如果name相同,则按生日日期的先后排序。【即:定制排序】

    2.  Employee.java:
       package com.hspedu.generic;
      
       public class Employee {
           private String name;
           private double sal;
           private MyDate birthday;
      
           public Employee(String name, double sal, MyDate birthday) {
               this.name = name;
               this.sal = sal;
               this.birthday = birthday;
           }
      
           public String getName() {
               return name;
           }
      
           public void setName(String name) {
               this.name = name;
           }
      
           public double getSal() {
               return sal;
           }
      
           public void setSal(double sal) {
               this.sal = sal;
           }
      
           public MyDate getBirthday() {
               return birthday;
           }
      
           public void setBirthday(MyDate birthday) {
               this.birthday = birthday;
           }
      
           @Override
           public String toString() {
               return "\nEmployee{" +
                       "name='" + name + '\'' +
                       ", sal=" + sal +
                       ", birthday=" + birthday +
                       '}';
           }
       }
       =========================================================================
       MyDate.java:
       package com.hspedu.generic;
      
       public class MyDate implements Comparable<MyDate>{
           private int year;
           private int month;
           private int day;
      
           public MyDate(int year, int month, int day) {
               this.year = year;
               this.month = month;
               this.day = day;
           }
      
           public int getYear() {
               return year;
           }
      
           public void setYear(int year) {
               this.year = year;
           }
      
           public int getMonth() {
               return month;
           }
      
           public void setMonth(int month) {
               this.month = month;
           }
      
           public int getDay() {
               return day;
           }
      
           public void setDay(int day) {
               this.day = day;
           }
      
           @Override
           public String toString() {
               return "MyDate{" +
                       "year=" + year +
                       ", month=" + month +
                       ", day=" + day +
                       '}';
           }
      
           @Override
           public int compareTo(MyDate o) { //把对year-month-day比较放在这里
      
               int yearMinus = year - o.getYear();
               if(yearMinus != 0) {
                   return  yearMinus;
               }
               //如果year相同,就比较month
               int monthMinus = month - o.getMonth();
               if(monthMinus != 0) {
                   return monthMinus;
               }
               //如果year 和 month
               return day - o.getDay();
           }
       }
       =========================================================================
       GenericExercise02.java:
       package com.hspedu.generic;
      
       import java.util.ArrayList;
       import java.util.Comparator;
      
      
       @SuppressWarnings({"all"})
       public class GenericExercise02 {
           public static void main(String[] args) {
      
               ArrayList<Employee> employees = new ArrayList<>();
               employees.add(new Employee("tom", 20000, new MyDate(1980,12,11)));
               employees.add(new Employee("jack", 12000, new MyDate(2001,12,12)));
               employees.add(new Employee("tom", 50000, new MyDate(1980,12,10)));
      
               System.out.println("employees=" + employees);
      
      
               employees.sort(new Comparator<Employee>() {
                   @Override
                   public int compare(Employee emp1, Employee emp2) {
                       //先按照name排序,如果name相同,则按生日日期的先后排序。【即:定制排序】
                       //先对传入的参数进行验证
                       if(!(emp1 instanceof  Employee && emp2 instanceof Employee)) {
                           System.out.println("类型不正确..");
                           return 0;
                       }
                       //比较name
                       int i = emp1.getName().compareTo(emp2.getName());
                       if(i != 0) {
                           return i;
                       }
      
                       //下面是对birthday的比较,因此,我们最好把这个比较,放在MyDate类完成
                       //封装后,将来可维护性和复用性,就大大增强.
                       return emp1.getBirthday().compareTo(emp2.getBirthday());
                   }
               });
      
               System.out.println("==对雇员进行排序==");
               System.out.println(employees);
      
           }
       }
       /**
        * 定义Employee类
        * 1) 该类包含:private成员变量name,sal,birthday,其中 birthday 为 MyDate 类的对象;
        * 2) 为每一个属性定义 getter, setter 方法;
        * 3) 重写 toString 方法输出 name, sal, birthday
        * 4) MyDate类包含: private成员变量month,day,year;并为每一个属性定义 getter, setter 方法;
        * 5) 创建该类的 3 个对象,并把这些对象放入 ArrayList 集合中(ArrayList 需使用泛型来定义),对集合中的元素进行排序,并遍历输出:
        *
        * 排序方式: 调用ArrayList 的 sort 方法 ,
        * 传入 Comparator对象[使用泛型],先按照name排序,如果name相同,则按生日日期的先后排序。【即:定制排序】
        * 有一定难度 15min , 比较经典 泛型使用案例 GenericExercise02.java
        */
      
       输出结果:
       employees=[
       Employee{name='tom', sal=20000.0, birthday=MyDate{year=1980, month=12, day=11}}, 
       Employee{name='jack', sal=12000.0, birthday=MyDate{year=2001, month=12, day=12}}, 
       Employee{name='tom', sal=50000.0, birthday=MyDate{year=1980, month=12, day=10}}]
       ==对雇员进行排序==
       [
       Employee{name='jack', sal=12000.0, birthday=MyDate{year=2001, month=12, day=12}}, 
       Employee{name='tom', sal=50000.0, birthday=MyDate{year=1980, month=12, day=10}}, 
       Employee{name='tom', sal=20000.0, birthday=MyDate{year=1980, month=12, day=11}}]
      
      1. 思考:

        1. 这里的主要精彩之处在于将比较年龄放在MyDate类里和sort方法中的两个conpareTo方法(142和149行)是不一样的,接下来我会讲下为什么能放入以及为什么不一样

        2. 首先我们在Employee类中可以看到name的返回类型为string,而birthday的返回类型为Mydate

        3. 在Mydate类中MyDate声明中实现Comparable​接口并对compareTo​方法进行重写并使用MyDate泛型

        4. 当编辑器运行到compareTo​方法时看到getName​类型为String时就会运行到内部的方法,看到getBirthday​类型为MayDate时就会运行到MyDate方法里

自定义泛型

  1. 自定义泛型类

    1. 语法

      1. class 类名 <T,R…>{//…表示可以有多个泛型
        成员
        }
    2. 注意细节

      1. 普通成员可以使用泛型(属性、方法)
      2. 使用泛型的数组,不能初始化
      3. 静态方法中不能使用类的泛型
      4. 泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
      5. 如果在创建对象时,没有指定类型,默认为Object
    3. 代码示例

      1.  package com.hspedu.customgeneric;
        
        
         import java.util.Arrays;
        
         @SuppressWarnings({"all"})
         public class CustomGeneric_ {
             public static void main(String[] args) {
        
                 //T=Double, R=String, M=Integer
                 Tiger<Double,String,Integer> g = new Tiger<>("john");
                 g.setT(10.9); //OK
                 //g.setT("yy"); //错误,类型不对
                 System.out.println(g);
                 Tiger g2 = new Tiger("john~~");//OK T=Object R=Object M=Object
                 g2.setT("yy"); //OK ,因为 T=Object "yy"=String 是Object子类
                 System.out.println("g2=" + g2);
        
             }
         }
        
         //解读
         //1. Tiger 后面泛型,所以我们把 Tiger 就称为自定义泛型类
         //2, T, R, M 泛型的标识符, 一般是单个大写字母
         //3. 泛型标识符可以有多个.
         //4. 普通成员可以使用泛型 (属性、方法)
         //5. 使用泛型的数组,不能初始化
         //6. 静态方法中不能使用类的泛型
         class Tiger<T, R, M> {
             String name;
             R r; //属性使用到泛型
             M m;
             T t;
             //因为数组在new 不能确定T的类型,就无法在内存开空间
             T[] ts;
        
             public Tiger(String name) {
                 this.name = name;
             }
        
             public Tiger(R r, M m, T t) {//构造器使用泛型
        
                 this.r = r;
                 this.m = m;
                 this.t = t;
             }
        
             public Tiger(String name, R r, M m, T t) {//构造器使用泛型
                 this.name = name;
                 this.r = r;
                 this.m = m;
                 this.t = t;
             }
        
             //因为静态是和类相关的,在类加载时,对象还没有创建
             //所以,如果静态方法和静态属性使用了泛型,JVM就无法完成初始化
         //    static R r2;
         //    public static void m1(M m) {
         //
         //    }
        
             //方法使用泛型
        
             public String getName() {
                 return name;
             }
        
             public void setName(String name) {
                 this.name = name;
             }
        
             public R getR() {
                 return r;
             }
        
             public void setR(R r) {//方法使用到泛型
                 this.r = r;
             }
        
             public M getM() {//返回类型可以使用泛型.
                 return m;
             }
        
             public void setM(M m) {
                 this.m = m;
             }
        
             public T getT() {
                 return t;
             }
        
             public void setT(T t) {
                 this.t = t;
             }
        
             @Override
             public String toString() {
                 return "Tiger{" +
                         "name='" + name + '\'' +
                         ", r=" + r +
                         ", m=" + m +
                         ", t=" + t +
                         ", ts=" + Arrays.toString(ts) +
                         '}';
             }
         }
         //Tiger{name='john', r=null, m=null, t=10.9, ts=null}
         //g2=Tiger{name='john~~', r=null, m=null, t=yy, ts=null}
        
  2. 自定义泛型接口

    1. 基本语法

      1. interface 接口名 <T,R…>{
        }
    2. 注意细节

      1. 接口中,静态成员也不能使用泛型(这个和泛型类规定一样)
      2. 泛型接口的类型,在继承接口或者实现接口时确定
      3. 没有指定类型,默认为Object
    3. 代码示例

      1.  package com.hspedu.customgeneric;
        
         public class CustomInterfaceGeneric {
             public static void main(String[] args) {
        
             }
         }
        
         /**
          *  泛型接口使用的说明
          *  1. 接口中,静态成员也不能使用泛型
          *  2. 泛型接口的类型, 在继承接口或者实现接口时确定
          *  3. 没有指定类型,默认为Object
          */
        
         //在继承接口 指定泛型接口的类型
         interface IA extends IUsb<String, Double> {
        
         }
         //当我们去实现IA接口时,因为IA在继承IUsu 接口时,指定了U 为String R为Double
         //,在实现IUsu接口的方法时,使用String替换U, 是Double替换R
         class AA implements IA {
        
             @Override
             public Double get(String s) {
                 return null;
             }
             @Override
             public void hi(Double aDouble) {
        
             }
             @Override
             public void run(Double r1, Double r2, String u1, String u2) {
        
             }
         }
        
         //实现接口时,直接指定泛型接口的类型
         //给U 指定Integer 给 R 指定了 Float
         //所以,当我们实现IUsb方法时,会使用Integer替换U, 使用Float替换R
         class BB implements IUsb<Integer, Float> {
        
             @Override
             public Float get(Integer integer) {
                 return null;
             }
        
             @Override
             public void hi(Float aFloat) {
        
             }
        
             @Override
             public void run(Float r1, Float r2, Integer u1, Integer u2) {
        
             }
         }
         //没有指定类型,默认为Object
         //建议直接写成 IUsb<Object,Object>
         class CC implements IUsb { //等价 class CC implements IUsb<Object,Object> {
             @Override
             public Object get(Object o) {
                 return null;
             }
             @Override
             public void hi(Object o) {
             }
             @Override
             public void run(Object r1, Object r2, Object u1, Object u2) {
        
             }
        
         }
        
         interface IUsb<U, R> {
        
             int n = 10;
             //U name; 不能这样使用
        
             //普通方法中,可以使用接口泛型
             R get(U u);
        
             void hi(R r);
        
             void run(R r1, R r2, U u1, U u2);
        
             //在jdk8 中,可以在接口中,使用默认方法, 也是可以使用泛型
             default R method(U u) {
                 return null;
             }
         }
         //编译成功
        
  3. 自定义泛型方法

    1. 基本语法

      1. 修饰符 <T,R…> 返回类型 方法名(参数列表){
        }
    2. 使用细节

      1. 泛型方法,可以定义在普通类中,也可以定义在泛型类中
      2. 当泛型方法被调用时,类型会确定
      3. public void eat(E e){},修饰符后没有<T,R…> eat方法不是泛型方法,而是使用了泛型
    3. 代码示例

      1.  package com.hspedu.customgeneric;
        
         import java.util.ArrayList;
        
         @SuppressWarnings({"all"})
         public class CustomMethodGeneric {
             public static void main(String[] args) {
                 Car car = new Car();
                 car.fly("宝马", 100);//当调用方法时,传入参数,编译器,就会确定类型
                 System.out.println("=======");
                 car.fly(300, 100.1);//当调用方法时,传入参数,编译器,就会确定类型
        
                 //测试
                 //T->String, R-> ArrayList
                 Fish<String, ArrayList> fish = new Fish<>();
                 fish.hello(new ArrayList(), 11.3f);
             }
         }
        
         //泛型方法,可以定义在普通类中, 也可以定义在泛型类中
         class Car {//普通类
        
             public void run() {//普通方法
             }
             //说明 泛型方法
             //1. <T,R> 就是泛型
             //2. 是提供给 fly使用的
             public <T, R> void fly(T t, R r) {//泛型方法
                 System.out.println(t.getClass());//String
                 System.out.println(r.getClass());//Integer
             }
         }
        
         class Fish<T, R> {//泛型类
             public void run() {//普通方法
             }
             public<U,M> void eat(U u, M m) {//泛型方法
        
             }
             //说明
             //1. 下面hi方法不是泛型方法
             //2. 是hi方法使用了类声明的 泛型
             public void hi(T t) {
             }
             //泛型方法,可以使用类声明的泛型,也可以使用自己声明泛型
             public<K> void hello(R r, K k) {
                 System.out.println(r.getClass());//ArrayList
                 System.out.println(k.getClass());//Float
             }
        
         }
         输出结果:
         class java.lang.String
         class java.lang.Integer
         =======
         class java.lang.Integer
         class java.lang.Double
         class java.util.ArrayList
         class java.lang.Float
        
  4. 泛型通配符

    1. 介绍

      1. 泛型不具备继承性
      2. <?>:支持任意泛型类型
      3. <? extends A>:支持A类以及A类的子类,规定了泛型的上限
      4. <?super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限
    2. 代码示例

      1.  package com.hspedu;
        
         import java.util.ArrayList;
         import java.util.List;
        
         public class GenericExtends {
             public static void main(String[] args) {
        
                 Object o = new String("xx");
        
                 //泛型没有继承性
                 //List<Object> list = new ArrayList<String>();
        
                 //举例说明下面三个方法的使用
                 List<Object> list1 = new ArrayList<>();
                 List<String> list2 = new ArrayList<>();
                 List<AA> list3 = new ArrayList<>();
                 List<BB> list4 = new ArrayList<>();
                 List<CC> list5 = new ArrayList<>();
        
                 //如果是 List<?> c ,可以接受任意的泛型类型
                 printCollection1(list1);
                 printCollection1(list2);
                 printCollection1(list3);
                 printCollection1(list4);
                 printCollection1(list5);
        
                 //List<? extends AA> c: 表示 上限,可以接受 AA或者AA子类
         //        printCollection2(list1);//×
         //        printCollection2(list2);//×
                 printCollection2(list3);//√
                 printCollection2(list4);//√
                 printCollection2(list5);//√
        
                 //List<? super AA> c: 支持AA类以及AA类的父类,不限于直接父类
                 printCollection3(list1);//√
                 //printCollection3(list2);//×
                 printCollection3(list3);//√
                 //printCollection3(list4);//×
                 //printCollection3(list5);//×
        
        
                 //冒泡排序
        
                 //插入排序
        
                 //....
        
        
             }
             // ? extends AA 表示 上限,可以接受 AA或者AA子类
             public static void printCollection2(List<? extends AA> c) {
                 for (Object object : c) {
                     System.out.println(object);
                 }
             }
        
             //说明: List<?> 表示 任意的泛型类型都可以接受
             public static void printCollection1(List<?> c) {
                 for (Object object : c) { // 通配符,取出时,就是Object
                     System.out.println(object);
                 }
             }
        
        
        
             // ? super 子类类名AA:支持AA类以及AA类的父类,不限于直接父类,
             //规定了泛型的下限
             public static void printCollection3(List<? super AA> c) {
                 for (Object object : c) {
                     System.out.println(object);
                 }
             }
        
         }
        
         class AA {
         }
        
         class BB extends AA {
         }
        
         class CC extends BB {
         }
         //编译成功
        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2216968.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解 KMP 算法

《深入理解 KMP 算法》 在计算机科学中&#xff0c;字符串匹配是一个常见且重要的问题&#xff0c;而 KMP&#xff08;Knuth - Morris - Pratt&#xff09;算法则是一种高效的字符串匹配算法。 一、KMP 算法的背景 在传统的字符串匹配算法中&#xff0c;当遇到不匹配的字符时…

基于AES的遥感图像加密算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 AES 加密算法概述 4.2 基于 AES 的遥感图像加密算法原理 5.完整程序 1.程序功能描述 通过AES算法对遥感图像进行加密和解密&#xff0c;分析加解密处理后图像的直方图&#xff0c;相关…

React之组件渲染性能优化

关键词&#xff1a; shouldComponentUpdate、PureComnent、React.memo、useMemo、useCallback shouldComponentUpdate 与 PureComnent shouldComponentUpdate 与 PureComnent 用于类组件。虽然官方推荐使用函数组件&#xff0c;但我们依然需要对类组件的渲染优化策略有所了解…

jar 导入本地和远程私服 maven 仓库

jar 导入本地和远程私服 maven 仓库artemis-http-client 认证库 maven 坐标为&#xff1a; 执行 mvn 命令&#xff1a; mvn install:install-file -DfileD:\download\lib\artemis-http-client-1.1.12.RELEASE.jar -DgroupIdcom.hikvision.ga -DartifactIdartemis-http-clien…

图像中的融合

图像显示函数 def img_show(name, img):"""显示图片:param name: 窗口名字:param img: 图片对象:return: None"""cv2.imshow(name, img)cv2.waitKey(0)cv2.destroyAllWindows()图像读取与处理 读取图片 cloud cv2.imread(bg.jpg) fish cv2.…

C++ | Leetcode C++题解之第485题最大连续1的个数

题目&#xff1a; 题解&#xff1a; class Solution { public:int findMaxConsecutiveOnes(vector<int>& nums) {int maxCount 0, count 0;int n nums.size();for (int i 0; i < n; i) {if (nums[i] 1) {count;} else {maxCount max(maxCount, count);coun…

【二刷hot-100】day1

目录 1.两数之和 2.字母异位词分组 3.字母异位词分组 4.最长连续序列 5.移动零 6.盛最多水的容器 7.三数之和 8.接雨水 1.两数之和 class Solution {public int[] twoSum(int[] nums, int target) {Map<Integer,Integer> mapnew HashMap<>();for (int i0;i<…

10.16标准IO

1、完成标准IO的单字符、字符串、格式化、模块化实现两个文件的拷贝&#xff1b; 单字符实现 #include <myhead.h> int main(int argc, const char *argv[]) {//使用单字符完成两个文件拷贝FILE *fp_srcfopen(argv[1],"r");FILE *fp_destfopen(argv[2],"…

猪圈密码简单实例

猪圈密码简单实例 猪圈密码表 根据上面的密码表&#xff0c;得到每个字母所对应的符号如下 例如单词the的加密结果为&#xff1a;

IO编程--单字符、字符串、格式化、模块化实现文件拷贝以及登录注册

一、完成标准io的单字符、字符串、格式化、模块化实现两个文件的拷贝 代码如下&#xff1a; 1.单字符 #include <myhead.h> int main(int argc, const char *argv[]) {//打开文件FILE* fpfopen("test.txt","r"); FILE* fqfopen("copy_test.txt&…

leetcode:744. 寻找比目标字母大的最小字母(python3解法)

难度&#xff1a;简单 给你一个字符数组 letters&#xff0c;该数组按非递减顺序排序&#xff0c;以及一个字符 target。letters 里至少有两个不同的字符。 返回 letters 中大于 target 的最小的字符。如果不存在这样的字符&#xff0c;则返回 letters 的第一个字符。 示例 1&a…

2024国际潜水小姐大赛中国区总决赛盛典在广州举行,吉林选手张潇文获冠军!

传承“以美之名&#xff0c;保护海洋”的精神&#xff0c;2024年10月15日晚&#xff0c;2024国际潜水小姐大赛中国区总决赛盛典在广州渔民新村隆重举行&#xff01;来自全国多个城市&#xff0c;经过层层选拔产生的20位佳丽齐聚广州&#xff0c;以独特的女性水下之美和健康美&a…

初识算法 · 二分查找(1)

目录 前言&#xff1a; 二分查找 题目解析 算法原理 算法编写 搜索插入位置 题目解析 算法原理 算法编写 前言&#xff1a; 本文呢&#xff0c;我们从滑动窗口窗口算法移步到了二分查找算法&#xff0c;我们简单了解一下二分查找算法&#xff0c;二分查找算法是一个十…

安科瑞末端组合式智慧用电装置在高校宿舍中的应用

1相关背景 学校宿舍用电隐患 安全用电历来都是学校安全工作的一个重点&#xff0c;然而每年因此发生的人身伤害以及火灾事故却在继续&#xff0c;究其原因&#xff0c;主观上是我们的防患意识淡薄&#xff0c;客观上则是由于学生在宿舍使用违规电器、乱拉电线造成的。 现代的…

Java IO 基础知识

IO 流简介 IO 即 Input/Output&#xff0c;输入和输出。数据输入到计算机内存的过程即输入&#xff0c;反之输出到外部存储&#xff08;比如数据库&#xff0c;文件&#xff0c;远程主机&#xff09;的过程即输出。数据传输过程类似于水流&#xff0c;因此称为 IO 流。IO 流在…

java关于如何实现读取各种类型的文件核心属性方法,比如获取标题和作者、主题等;附带远程的https的地址文件读取方法;

有两种方法&#xff1a; 通过提供的现成api进行调用读取pdf文件&#xff0c;或doc、xlsx、pptx文件&#xff1b;可能商业需要付费 https://www.e-iceblue.cn/pdf_java_document_operation/set-pdf-document-properties-in-java.html Spire.PDF for Java import com.spire.pdf…

为什么SSH协议是安全的?

SSH的传输层协议&#xff08;Transport Layer Protocol&#xff09;和用户鉴权协议&#xff08;Authentication Protocol&#xff09;确保数据的传输安全&#xff0c;这里只介绍传输层协议&#xff0c;是SSH协议的基础。 本文针对SSH2协议。 1、客户端连接服务器 服务器默认…

基于springboot实习管理系统

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 系统展示 【2024最新】基于JavaSpringBootVueMySQL的&#xff0c;前后端分离。 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;…

k8s use-context是什么

kubectl 的 use-context 命令用于在 Kubernetes 集群中切换上下文&#xff08;context&#xff09;&#xff0c;从而方便地在多个集群或命名空间之间进行操作。一个上下文定义了 kubectl 使用的 集群、用户 和 命名空间 的组合。 use-context 的作用&#xff1a; 每个上下文&…

msql事务隔离级别 线上问题

1. 对应代码 解决方式&#xff1a; 在事务隔离级别为可重复读&#xff08;RR&#xff09;时&#xff0c;数据库确实通常会记录当前数据的快照。 在可重复读隔离级别下&#xff0c;事务在执行期间看到的数据是事务开始时的数据快照&#xff0c;即使其他事务对数据进行了修改&am…