java学习

 一、前言

  • 1、JRE和JDK

    • JRE
      • Java程序的运行环境,包含JVM(Java虚拟机)和运行时所需要的核心类库
    • JDK
      • Java程序开发工具包,包含JRE和开发人员使用的工具(编译工具:javac.exe  运行工具:java.exe)
        • 编译java代码:javac xx.java
        • 解释执行字节码:java xx
  • 2、JDK的下载与安装

    • 下载地址:https://www.oracle.com/java/technologies/downloads/
    • 安装后关闭Java自动检查更新:
      • 开始菜单 - Java - 检查更新 - 取消自动检查更新  - 不检查
    • 配置环境变量
      • 添加系统环境变量JAVA_HOME,指向JDK安装目录,比如:D:\Softwares\Java\jdk1.8.0_181
      • 编辑系统环境变量path,添加:%JAVA_HOME%\bin
  • 3、IDEA下载与安装

    • Java开发的集成环境
    • 官方下载地址:https://www.jetbrains.com/idea/
    • 配置日志、插件等目录
      • 默认在 c 盘,建议配置到其它盘,减轻c盘压力
      • 打开安装目录/bin目录下的文件idea.properties,将前面4条注释过的路径打开,然后进行配置,比如
        # Uncomment this option if you want to customize a path to the settings directory.
        #---------------------------------------------------------------------
        idea.config.path=E:/ProgramFiles/.IntelliJIdea/config
        
        #---------------------------------------------------------------------
        # Uncomment this option if you want to customize a path to the caches directory.
        #---------------------------------------------------------------------
        idea.system.path=E:/ProgramFiles/.IntelliJIdea/system
        
        #---------------------------------------------------------------------
        # Uncomment this option if you want to customize a path to the user-installed plugins directory.
        #---------------------------------------------------------------------
        idea.plugins.path=E:/ProgramFiles/.IntelliJIdea/plugins
        
        #---------------------------------------------------------------------
        # Uncomment this option if you want to customize a path to the logs directory.
        #---------------------------------------------------------------------
        idea.log.path=E:/ProgramFiles/.IntelliJIdea/log
        View Code
    • 常用快捷键
      • alt + 回车:万能纠错 / 生成返回值变量
      • shift + f6:重命名文件 / 变量(修改多个)
      • ctrl + f / ctrl + shift +f:局部 / 全局搜索
      • ctrl + r / ctrl + shift + r:局部 / 全局替换
      • ctrl + shift + v:粘贴历史内容
      • ctrl + d:代码行复制
      • ctrl + shift + e / ctr + e:查看最近访问过的本地 / 全局文件
      • ctrl + q:提示方法的参数及类型
      • ctrl + shift + u:全大写 / 小写切换
      • alt + shift + 上 / 下键:代码行整体上 / 下移
      • ctrl + /:代码注释
      • 选中多排 + tab:整体右移
      • 选中多排 + shift + tab:整体左移
      • ctrl + z:撤销
      • ctrl + shift + z:反撤销
      • shift + 回车:向下开始新的一行
      • ctrl + alt + 回车:向上开始新的一行
      • ctrl + alt + l:代码格式化
      • ctr + alt + v:快速补全对象调用方法后的返回值及类型
  • 4、设置cmd命令行默认编码为UTF-8

    • 通过win+r打开开始菜单搜索框,输入regedit
    • 依次找到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor
    • 然后在右边空白处右键新建,选择‘字符串值’,名称填写autorun
    • 然后在autorun上右键-修改,在数值数据中输入‘chcp 65001’
  • 5、windows terminal常用快捷键

    • 新建选项卡
      • ctr + shift + d
    • 划分窗格
      • alt + shift + ( d 或者 - 或者 +)
    • 关闭窗格
      • ctr + shift + w
    • 切换窗格
      • alt + 方向键
    • 调整窗格大小
      • alt + shift + 方向键

二、类和对象

  • 1、类

    • 类是Java程序的基本组成单位,是对现实生活中一类具有共同属性行为的事物的抽象,确定对象将会拥有的属性和行为
      • 属性:在类中通过成员变量来体现
      • 行为:在类中通过成员方法来体现
    • 定义
      public class 类名{
          // 成员变量
          变量1的数据类型 变量1;
          变量2的数据类型 变量2;
          ...
          
          // 成员方法
          方法1;
          方法2;
          ...
      }
  • 2、对象

    • 创建对象
      • 类名 对象名= new 类名();
    • 使用对象
      • 使用成员变量
        • 对象名.变量名
      • 使用成员方法
        • 对象名.方法名()
    • 示例
      public class PhoneDemo {
          public static void main(String[] args) {
              // 创建对象
              Phone p = new Phone();
      
              // 使用成员变量
              System.out.println(p.brand); // 默认值 null
              System.out.println(p.price); // 默认值 0
      
              // 修改成员变量
              p.brand = "苹果";
              p.price = 9999;
              System.out.println(p.brand);
              System.out.println(p.price);
      
              //使用成员方法
              p.call();
              p.sendMessage();
          }
      }
      
      class Phone{
          // 成员变量
          String brand;
          int price;
      
          // 成员方法
          public void call(){
              System.out.println("打电话");
          }
      
          public void sendMessage(){
              System.out.println("发短信");
          }
      }
  • 3、成员变量和局部变量

    • 成员变量:类中方法外的变量
    • 局部变量:方法中的变量
  • 4、包

    • 作用
      • 区分相同名字的类
      • 控制访问范围
      • 当类很多时,便于管理
    • 建包
      • 实际上就是创建不同的文件夹 / 目录来保存类文件
    • 打包
      • package 包名;
      • package的作用是声明当前类所在的包,需要放在最上面,一个类中只能有一个pakcage
    • 导包
      • import  xxx;
      • java.lang.*是基本包,默认引入,不要导入
    • jar包
      • 制作
        • jar cvf xx.jar foo/ .      将foo目录下的所有文件打包成xx.jar
      • 查看
        • jar tf xx.jar
      • 运行
        • java -jar xx.jar
      • 其它参数,可使用: jar --help 查看
  • 5、this关键字

    • this:代表本类对象的引用
    • 用于解决方法中形参和成员变量同名问题
      • 如果方法中形参和成员变量同名,不带this修饰的变量指向形参,使用this修饰的变量是成员变量
      • 对于形参没有与成员变量同名的情况下,使用成员变量时可省略this修饰
    • 方法被哪个对象调用,this就代表哪个对象
    • 用法:
      • this.成员变量:访问成员变量
      • this(...) :访问本类构造方法
      • this.成员方法(...):访问本类成员方法
  • 6、super关键字

    • super关键字的用法和this关键字相似
    • super:代表父类存储空间的标识(可以理解为父类对象引用)
    • 用法:
      • super.成员变量:访问父类成员变量
      • super(...):访问父类构造方法
      • super.成员方法(...):访问父类成员方法
  • 7、修饰符

    • 分类
      • 权限修饰符
      • 状态修饰符
    • 权限修饰符
      • private:只能在本类中访问
      • 没有修饰符(默认):本类 + 同包
      • protected:本类 + 同包 + 子类
      • public:本类 + 同包 + 子类 + 不同包
        • 注意:只有默认修饰符和public能够修饰类
    • 状态修饰符
      • final(最终态)
        • 被修饰的类,不能被继承(最终类)
        • 被修饰的方法,不能被重写(最终方法)
        • 被修饰的变量,不能被再次赋值(常量)
          • 变量是基本类型数据值不能发生改变
          • 变量是引用类型地址值不能发生改变,但是地址里面的内容可以改变
      • static(静态)
        • 静态成员变量:被类的所有对象共享,既可以通过对象名调用,也可以通过类名调用(推荐使用类名调用
        • 静态成员方法:只能访问静态成员
  • 8、封装

    • 概述
      • 是面向对象三大特征之一(封装、继承、多态)
    • 原则
      • 将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问
      • 成员变量使用private关键字修饰,提供对应的 get() 和 set() 方法
        public class Student {
            private String name;
        
            public String getName() {
                return name;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        }
    • 好处
      • 通过方法来控制成员变量的操作,提高了代码的安全性
      • 把代码用方法进行封装,提高了代码的复用性
  • 9、构造方法(构造器)

    • 概述
      • 构造方法是一种特殊的方法,主要是完成对象数据的初始化
    • 格式
      public class 类名{
          修饰符 类名(参数){
              // 构造方法内书写的内容
          }
      }
    • 注意事项
      • 如果没有定义构造方法,系统将给出一个默认无参数构造方法
      • 如果定义了构造方法,系统不再提供默认的构造方法
      • 如果自定义了带参构造方法,还要使用无参数构造方法,就必须再写一个无参数构造方法
      • 建议:无论是否使用,都手动书写无参数构造方法
        public class Student {
            private String name;
            private int age;
        
            // 无参数构造方法
            public Student() {
            }
        
            // 有参数构造方法
            public Student(String name, int age) {
                this.name = name;
                this.age = age;
            }
        }
  • 10、继承

    • 概述
      • 可以使得子类具有父类的属性和方法,还可以在子类中重新定义、追加方法和属性
    • 格式
      • class 子类名 extends 父类名{ }
        • 父类:也被称为基类、超类

        • 子类:也被称为派生类
    • 继承好处
      • 提高代码复用性(多个类相同的成员可以放到哦同一个类中)
      • 提高代码维护性(如果方法的代码需要修改,修改一处即可)
    • 继承中变量访问特点
      • 子类局部范围找
      • 子类成员范围找
      • 父类成员范围找
      • 如果都没有就报错(不考虑祖先的情况下)
        public class Demo {
            public static void main(String[] args) {
                // 创建对象
                Son s = new Son();
        
                // 调用show()方法
                s.show();
            }
        }
        
        // 继承父类
        class Son extends Father {
            public int age = 20;
            public String gender = "男";
        
            // 重写show方法
            public void show() {
                int age = 22;
                System.out.println("age = " + age); // 22 => 使用局部变量
                System.out.println("gender = " + gender); // 男 => 使用成员变量
                System.out.println("height = " + height); // 180 => 使用父类变量
                System.out.println("weight = " + weight); // 报错
            }
        }
        
        class Father {
            public int age = 45;
            public int height = 180;
        
            public void show() {
                System.out.println("age = " + age);
            }
        }
    • 继承中构造方法访问特点
      • 子类中所有的构造方法,默认都会访问父类中无参的构造方法
        • 因为子类会继承父类中的数据,可能还会使用父类的数据。所以子类初始化之前,一定要先完成父类数据的初始化
        • 每一个子类构造方法的第一条语句,默认都是:super()
      • 如果父类中没有无参构造方法,如何继承?
        • 在父类中提供一个无参构造方法(推荐)
        • 在子类构造方法第一行,通过super关键字去显示调用父类的带参构造方法
    • 继承中成员方法访问特点
      • 子类成员范围找
      • 父类成员范围找
      • 如果都没有就报错(不考虑祖先的情况下)
    • 方法重写
      • 概述
        • 子类中出现了和父类一模一样的方法声明
      • @Override
        • 是一个注解(后面会学习到)
        • 可以帮助我们检查重写方法的方法声明正确性
      • 注意事项
        • 私有方法不能被重写(私有成员方法子类无法继承)
        • 子类方法访问权限不能更低(public > 默认 > 私有)
    • 继承注意事项:
      • Java中类只支持单继承(extends后不能出现多个类)
      • Java中类支持多层继承
  • 11、多态

    • 概述
      • 同一个对象,在不同时刻表现出来的不同形态
      • 举例:猫
        • 可以说猫是猫:猫 cat = new 猫();
        • 也可以说猫是动物:动物 animal = new 猫();
        • 这里猫在不同时刻表现出来的不同形态,就是多态
    • 多态的前提和体现
      • 有继承 / 实现关系
      • 有方法重写
      • 有父(类 / 接口)引用指向(子 / 实现)类对象
    • 多态中成员访问特点
      • 成员变量:编译看左边,执行看左边
      • 成员方法:编译看左边,执行看右边
      • 原因:
        • 成员方法有重写,而成员变量没有
          public class Demo {
              public static void main(String[] args) {
                  // 有父类引用指向子类对象
                  Animal a = new Cat();
          
                  // 执行时看右边,调用cat的eat方法
                  a.eat();
          
                  // 执行时看左边,输出动物的category
                  System.out.println(a.category);
          
                  // 动物没有show方法,无法通过编译
                  // a.show();
              }
          }
          
          // 猫继承动物类
          class Cat extends Animal {
              public String category = "猫";
          
              // 重写动物类eat()方法
              @Override
              public void eat() {
                  System.out.println("猫在吃东西");
              }
              public void show(){
                  System.out.println("我是一只小花猫");
              }
          }
          
          class Animal {
              public String category = "动物";
              public void eat() {
                  System.out.println("动物在吃东西");
              }
          }
    • 多态中的转型
      • 向上转型
        • 从子到父,父类引用指向子类对象
        • 示例:Anima a = new Cat();
      • 向下转型
        • 父类引用转为子类对象
          • 示例
            Animal  a = new Cat();
            // 向下转型
            Cat c = (Cat)a;
            
            // 接下来就可以调用Cat类中的特有方法
            c.xxx();

三、抽象类

  • 1、概述

    • 在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,则该类必须被定义为抽象类
  • 2、特点

    • 抽象类和抽象方法,必须使用abstract关键字修饰
    • 抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类
    • 抽象类不能实例化
      • 但是可以参照多态的方式,通过子类对象实例化,这叫抽象类多态
    • 抽象类的子类,要么重写抽象类中的所有抽象方法,要么也是抽象类
      public class Demo {
          public static void main(String[] args) {
              Animal a = new Cat();
              a.eat();
              a.sleep();
          }
      }
      
      class Cat extends Animal {
          @Override
          public void eat() {
              System.out.println("猫在吃东西");
          }
      }
      
      // 抽象类
      abstract class Animal {
          // 抽象方法
          public abstract void eat();
      
          public void sleep() {
              System.out.println("动物在睡觉");
          }
      }

四、接口

  • 1、概述

    • 接口是一种公共的规范标准,只要符合规范标准,大家都可以通用
    • Java中的接口更多的体现在对行为的抽象
  • 2、接口的特点

    • 接口用关键字interface修饰
      • public interface 接口名{ };
    • 类实现接口用implements表示
      • public 类名 implements 接口名{ };
    • 接口不能被实例化
      • 但是可以参照多态的方式,通过实现类对象实例化,这叫接口多态
      • 多态的形式:具体类多态、抽象类多态接口多态
    • 接口的实现类
      • 要么重写接口中的所有抽象方法
      • 要么是抽象类
        public class Demo {
            public static void main(String[] args) {
                // 接口多态
                Jumping j = new Cat();
                j.jump();
            }
        }
        
        // 类实现接口
        class Cat implements Jumping{
            @Override
            public void jump() {
                System.out.println("猫在跳跃");
            }
        }
        
        // 定义接口
        interface Jumping {
            public abstract void jump();
            // 等同于
            // void jump();
        }
  • 3、接口的成员特点

    • 成员变量
      • 只能是常量
      • 默认修饰符:public static final
    • 构造方法
      • 接口没有构造方法,因为接口主要是对行为进行抽象的,没有具体存在
      • 一个类如果没有父类,默认继承自Object类
    • 成员方法
      • 只能是抽象方法
      • 默认修饰符:publict abstract
    • 总结:只能是常量抽象方法
  • 4、类和接口的关系

    • 类和类的关系
      • 继承关系,只能单继承,但是可以多层继承
    • 类和接口的关系
      • 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
    • 接口和接口的关系
      • 继承关系,可以单继承,也可以多继承
        // 继承一个类的同时,实现多个接口
        public class InterImpl extends Object implements Inter1, Inter2, Inter3{
        
        }
        
        interface Inter1{
        
        }
        
        interface Inter2{
        
        }
        
        // 接口多继承
        interface Inter3 extends Inter1, Inter2{
        
        }

五、内部类

  • 1、内部类概述

    • 内部类:就是在一个类中定义一个类
    • 内部类定义格式:
      public class 类名{
          修饰符 class 类名{ 
          }
      }
    • 内部类访问特点:
      • 内部类可以直接访问外部类的成员,包括私有,同名的情况下,会就近使用内部类成员变量,如果要使用外部类成员变量,可以使用(外部类名.this.成员名
      • 外部类要访问内部类的成员,必须创建对象
        public class Outer{
            private int num = 30;
            public class Inner{
                public void show(){
                    // 访问外部类的私有成员变量
                    System.out.println(num);
                }
            }
            
            public void method(){
                // 外部类访问内部类,必须创建对象
                Inner i = new Inner();
                i.show();
            }
        }
  • 2、成员内部类

    • 在类的成员位置
    • 外界如何创建对象使用?
        • 格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象
        • 范例:Outer.Inner oi = new Outer().new Inner();
  • 3、局部内部类

    • 局部内部类是在方法中定义的类,外界无法直接使用,需要在方法内部创建对象并使用
    • 该类可以访问方法内的局部变量,也可以直接访问外部类的成员(外部类名.this.成员名
      package com.java.app;
      
      public class Demo {
          public static void main(String[] args) {
              Outer o = new Outer();
              o.method();
          }
      }
      
      class Outer {
          private int num = 30;
      
          public void method() {
              int num = 40;
              class Inner {
                  public void show() {
                      // 访问外部类成员
                      System.out.println(Outer.this.num); // 30
                      // 访问局部变量
                      System.out.println(num); // 40
                  }
              }
              // 内部创建对象并使用
              Inner i = new Inner();
              i.show();
          }
      }
  • 4、匿名内部类

    • 概述
      • 是局部内部类的一种特殊形式
    • 前提
      • 存在一个或者接口,这里的类可以是具体类,也可以是抽象类
    • 格式
      new 类名或者接口名(){
          重写方法;
      };
    • 本质
      • 是一个继承了该类或者实现了该接口的子类匿名对象
        public class Demo {
            public static void main(String[] args) {
                // 实例化对象
                Cat c = new Cat();
                
                // 传入一个实现了Jumping接口的匿名对象
                c.method(new Jumping() {
                    @Override
                    public void jump() {
                        System.out.println("猫在跳跃");
                    }
                });
                
                // 传入一个继承了Animal抽象类的匿名对象
                c.method2(new Animal() {
                    @Override
                    public void eat() {
                        System.out.println("猫在吃东西");
                    }
                });
            }
        }
        
        // 定义一个猫类
        class Cat{
            public void method(Jumping j){
                j.jump();
            }
            public void method2(Animal a){
                a.eat();
            }
        }
        
        // 定义抽象类
        abstract class Animal{
            public abstract void eat();
        }
        
        // 定义接口
        interface Jumping{
            void jump();
        }
  • 5、获取各内部类名称

    • 对象.getClass().getName()
    • 各内部类命名特点
      • 匿名内部类:外部类名$数字
        • 数字从1开始,比如第3个匿名内部类的名字:外部类名$3
      • 成员内部类和局部内部类命名规则相同,但是成员内部类会先加载
        • 在成员内部类和局部内部类名不重复的情况下,默认使用:外部类名$1内部类名
        • 类名重复的情况下,会依次使用:外部类名$1重复类名(成员内部类),外部类名$2重复类名(局部内部类)
          package com.java.app;
          
          public class Demo {
              public static void main(String[] args) {
                  // 实例化对象
                  Cat c = new Cat();
          
                  // 传入一个实现了Jumping接口的匿名对象
                  c.method(new Jumping() {
                      @Override
                      public void jump() {
                          System.out.println("猫在跳跃");
                      }
                  });
          
                  // 获取匿名类的名字
                  Jumping j = new Jumping() {
                      @Override
                      public void jump() {
                          System.out.println("跳跃~");
                      }
                  };
                  System.out.println(j.getClass().getName()); // com.java.app.Demo$2,因为前面定义过1个匿名内部类,占用了Demo$1
          
                  // 定义2个成员内部类
                  class Inner{
                  }
                  class Inner2{
                  }
                  // 获取成员内部类的名字
                  System.out.println(new Inner().getClass().getName()); //com.java.app.Demo$1Inner
                  System.out.println(new Inner2().getClass().getName()); //com.java.app.Demo$1Inner2
          
                  // 获取局部内部类的名字
                  Demo.test(); //com.java.app.Demo$2Inner
                  Demo.test2(); //com.java.app.Demo$3Inner
              }
          
              public static void test() {
                  // 局部内部类
                  class Inner {
                  }
                 // 获取局部内部类的名字
                  System.out.println(new Inner().getClass().getName());
              }
          
              public static void test2() {
                  // 局部内部类
                  class Inner {
                  }
                  // 获取局部内部类的名字
                  System.out.println(new Inner().getClass().getName());
              }
          }
          
          // 定义一个猫类
          class Cat{
              public void method(Jumping j){
                  j.jump();
              }
          }
          
          // 定义接口
          interface Jumping{
              void jump();
          }

六、枚举类

  • 1、概述

    • 枚举类是一种特殊的类,里面包含一组有限的只读对象,枚举是一组常量的集合
    • 使用关键字 enum 替代 class,会变成final类,并且隐示继承  Enum类
    • 枚举对象必须放在枚举类的第一行
    • 有多个枚举对象,使用逗号间隔,最后以分号结尾
    • 使用无参的构造器创建枚举对象,小括号可以省略
    • 枚举对象可以有多个属性
  • 2、枚举类常用方法

    public class Demo {
    
        @SuppressWarnings("all")
        public static void main(String[] args) throws Exception {
            Season spring = Season.SPRING;
            System.out.println(spring); // Season{name='春天', desc='暖和'}
    
            // 枚举类.valueof():将字符串转换成枚举对象,字符串必须为已有枚举对象名
            Season spring2 = Season.valueOf("SPRING");
            System.out.println(spring == spring2); // true,枚举对象只实例化一次
    
            // name():返回枚举对象的名字
            System.out.println(spring.name()); // SPRING
    
            // ordinal():返回枚举对象的次序/编号,从0开始
            System.out.println(spring.ordinal());
    
            // 枚举类.values():返回定义的所有枚举类对象
            for (Season season : Season.values()) {
                System.out.println("season = " + season.name);
            }
    
            Season autumn = Season.AUTUMN;
            // compareTo():返回枚举对象的相对位置(即各自的次序相减)
            System.out.println(spring.compareTo(autumn)); // 1 - 3 = -2
        }
    }
    
    enum Season{
        // 枚举对象放在首行,多个枚举对象使用逗号分隔,以分号结尾
        SPRING("春天", "暖和"), SUMMER("夏天", "炎热"), AUTUMN("秋天", "凉爽"), WINTER("冬天", "寒冷");
        public String name;
        public String desc;
    
        Season() {
        }
    
        Season(String name, String desc) {
            this.name = name;
            this.desc = desc;
        }
    
        @Override
        public String toString() {
            return "Season{" +
                    "name='" + name + '\'' +
                    ", desc='" + desc + '\'' +
                    '}';
        }
    }

七、数组

  • 1、定义

    • 数组(Array)是一种用于存储多个相同类型数据的存储模型
    • 格式
      • 数据类型[ ] 变量名  => int[ ] arr
      • 定义了一个int类型的数组,数组名是arr 
  • 2、初始化方式

    • 动态初始化
      • 初始化时只指定数组长度,由系统为数组分配初始值
      • 格式
        • 数据类型[ ] 变量名 = new 数据类型[数组长度]
        • 范例: int[ ] arr = new int[3];
    • 静态初始化
      • 初始化时指定每个元素的初始值,由系统决定数组长度
      • 格式
        • 数据类型[ ] 变量名 = new 数据类型[ ] {数据1, 数据2, 数据3, ...}
        • 范例: int[ ] arr = new int[ ]{1, 2, 3};
      • 简化格式
        • 数据类型[ ] 变量名 = {数据1, 数据2, 数据3, ...}
        • 范例:int[ ] arr = {1, 2, 3};
  • 3、常见操作

    • 遍历
      // 定义数组
      int[] arr = {11, 22, 33, 44, 55};
      
      // 通用格式遍历
      for (int index = 0; index < arr.length; index++) { // arr.length 表示数组的长度
          System.out.println(arr[index]); // 通过索引获取数组中的元素,索引从0开始
      }
    • 获取最值
      // 定义数组
      int[] arr = {35, 22, 41, 17, 26, 77, 49};
      
      // 定义变量,用于保存最大值,默认数组中的第一个值
      int max = arr[0];
      
      // 遍历数组,与数组中的其它元素挨个比较,将最大值保存到max变量中
      for (int index = 1; index < arr.length; index++) {
          if(arr[index] > max){
              max = arr[index];
          }
      }

八、Arrays

  • 1、概述

    • Arrays类包含用于操作数组的各种方法
  • 2、常用方法

    • Arrays.toString(int[] a):返回指定数组内容的字符串表示形式
    • Arrays.sort(int[] a):按照数字顺序排列指定数组
  • 3、工具类的设计思想

    • 构造方法使用private修饰
    • 成员用public static修饰

九、String

  • 1、概述

    • String类代表字符串,Java程序中所有的双引号字符串都是String类的对象
    • 字符串不可变,但是可以被共享
  • 2、构造方法

    • 示例
      // 1、创建一个空白字符串对象,不含有任何内容
      String s1 = new String();
      System.out.println("s1 = " + s1);
      
      // 2、根据字符数组的内容,来创建字符串对象
      String s2 = new String(new char[] {'a', 'b', 'c'});
      System.out.println("s2 = " + s2);
      
      // 3、根据字节数组的内容,来创建字符串对象
      String s3 = new String(new byte[] {97, 98, 99});
      System.out.println("s3 = " + s3);
      
      // 4、直接赋值
      String s4 = "abc";
      System.out.println("s4 = " + s4);
  • 3、String对象特点

    • 通过new关键字创建的字符串对象,每次new都会申请一个内存空间,即地址值不同
    • 通过直接赋值("xxx")形式给出的字符串,只要序列相同,JVM都只会建立一个String对象,并在字符串池中维护
  • 4、字符串比较

    • 比较地址值:==
      • 基本类型:比较的是数据值
      • 引用类型:比较的是地址值
    • 比较内容:对象.equals()
      • 将此字符串与指定对象进行比较,比较的是内容
    • 示例
      // 1、通过构造方法的形式得到对象
      String s1 = new String(new char[] {'a', 'b', 'c'});
      String s2 = new String(new char[] {'a', 'b', 'c'});// 2、通过直接赋值的方式得到对象
      String s3 = "abc";
      String s4 = "abc";
      
      // 3、比较地址值
      System.out.println(s1 == s2); // false => new出来的对象,拥有不同的地址值
      System.out.println(s3 == s4); // true => 直接赋值,只会建立一个对象
      
      // 4、比较内容
      System.out.println(s1.equals(s2)); // true => 比较的是内容
      System.out.println(s3.equals(s4)); // true => 比较的是内容
  • 5、常见操作

    • 遍历
      // 1、键盘录入字符串
      Scanner scanner = new Scanner(System.in);
      System.out.println("请输入字符串:");
      String s = scanner.nextLine();
      
      // 2、遍历字符串
      //      2.1 通过length()方法,获取字符串长度
      //      2.2 通过charAt(index)方法,获取指定索引字符
      for (int index = 0; index < s.length(); index++) {
          System.out.println(s.charAt(index));
      }

十、StringBuilder

  • 1、概述

    • 如果对字符串进行拼接操作,每次拼接都会构建一个新的String对象,既耗时,又浪费内存空间
    • StringBuilder是一个内容可变的字符串类,而String内容不可变
  • 2、构造方法

    // 1、创建一个空白可变字符串对象
    StringBuilder sb = new StringBuilder();
    System.out.println("sb = " + sb);
    System.out.println(sb.length());
    
    // 2、根据字符串内容,来创建可变字符串对象
    StringBuilder sb2 = new StringBuilder("hello world!");
    System.out.println("sb2 = " + sb2);
    System.out.println(sb2.length());
  • 3、添加和反转方法

    • append(任意类型):添加对象,并返回对象本身
    • reverse:返回相反的字符序列
      // 1、创建一个空白可变字符串对象
      StringBuilder sb = new StringBuilder();
      
      // 2、append(任意类型):添加数据,并返回对象本身
      sb.append("hello").append("world").append(100); // 链式编程
      System.out.println("sb = " + sb);
      
      // 3、reverse():反转字符串
      sb.reverse();
      System.out.println("sb = " + sb);
  • 4、StringBuilder和String相互转换

    • StringBuilder转String:调用StringBuilder对象的toString()方法
    • String转StringBuilder:通过StringBuilder的构造方法,传入String对象作为参数
      // 1、创建一个空白可变字符串对象
      StringBuilder sb1 = new StringBuilder();
      sb1.append("hello world");
      
      // 2、StringBuilder转String
      String s1 = sb1.toString();
      System.out.println("s1 = " + s1);
      
      // 3、定义一个String字符串
      String s2 = "hello";
      
      // 4、String转StringBuilder
      StringBuilder sb2 = new StringBuilder(s2);
      System.out.println("s2 = " + s2);

十一、Integer

  • 1、静态方法获取对象

    • Integer.valueOf(int i):返回表示指定的 int 值的 Integer 实例
    • Integer.valueOf(String s):返回一个保存指定值的 Integer 对象 String
  • 2、int 和 String 的相互转换

    • int 转 String
      • String.valueOf(int i)
    • String 转 int
      • Integer.parseInt(String s)

十二、异常

  • 1、概述

    • 异常:就是程序出现了不正常的情况
  • 2、异常处理

    • try...catch...
      • 格式
        try{
          可能出现异常的代码;
        }catch{
            异常的处理代码;
        }
    • throws
      • 格式
        throws 异常类名;

        注意:格式是跟在方法括号后面

  • 3、自定义异常

    • 格式
      public class 异常类名 extends Exception{
          无参构造
          带参构造
      }
    • 范例
      import java.util.Scanner;
      
      public class Demo {
          public static void main(String[] args) {
              // 实例化对象
              Teacher t = new Teacher();
              Scanner scanner = new Scanner(System.in);
              System.out.println("请输入分数:");
              int score = scanner.nextInt();
              try {
                  t.checkScore(score);
              } catch (ScoreException e) {
                  e.printStackTrace(); // 把异常的错误信息输出在控制台
              }
          }
      }
      
      class Teacher {
          public void checkScore(int score) throws ScoreException {
              if (score < 0 || score > 100) {
                  // 抛出自定义异常
                  throw new ScoreException("分数异常!");
              } else {
                  System.out.println("分数正常!");
              }
          }
      }
      
      // 自定义异常
      class ScoreException extends Exception {
          // 无参构造
          public ScoreException() {
          }
      
          // 带参构造
          public ScoreException(String message) {
              super(message);
          }
      }
  • 4、throws 和 throw 的区别

    • thorws
      • 用在方法声明后面,跟的是异常类名
      • 表示抛出异常,由该方法的调用者来处理
      • 表示出现异常的一种可能性,并不一定会发生这些异常
    • throw
      • 用在方法体内,跟的是异常对象名
      • 表示抛出异常,由方法体内的语句处理
      • 执行 throw 一定抛出了某种异常

十三、集合

  • 1、概述

    • 集合类的特点:提供一种存储空间可变的存储模型,存储的数据容量可以发生改变
  • 2、集合体系结构

      • 集合
        • Collection(单列
          • List(可重复
            • ArrayList红色背景的表示实现类,其余均是接口,下同
            • LinkedList
            • ...
          • Set(不可重复
            • HashSet
            • TreeSet
            • ...
        • Map(双列
          • HashMap
          • ...
  • 3、Collection集合

    • Collection集合概述
      • 是单列集合的顶层接口,它表示一组对象,这些对象也被称为Collection的元素
      • JDK不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现
    • 创建Collection集合的对象
      • 多态的方式
        • 比如:Collection<String> c = new ArrayList<String>();
    • Collection集合常用方法
      • add(E e):添加元素
      • remove(Object o):从集合中移除指定的元素
      • clear():清空集合中的元素
      • contains(Objecto):判断集合中是否存在指定的元素
      • isEmpty():判断集合是否为空
      • size():集合的长度,也就是集合中元素的个数
    • Collection集合的遍历
      • iterator:迭代器,集合的专用遍历方式
        • iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
        • 迭代器是通过集合的iterator()方法得到的,依赖于集合而存在
        • iterator的常用方法:
          • next():返回迭代中的下一个元素
          • hasNext():如果迭代具有更多元素,则返回true
            import java.util.ArrayList;
            import java.util.Collection;
            import java.util.Iterator;
            
            public class Demo {
                public static void main(String[] args) {
                    // 创建集合对象
                    Collection<String> c = new ArrayList<String>();
            
                    // 添加元素
                    c.add("hello");
                    c.add("world");
                    c.add("java");
            
                    // 通过集合的iterator()方法,获取该集合中元素的迭代器
                    Iterator<String> it = c.iterator();
            
                    // while循环遍历
                    while (it.hasNext()) {
                        String s = it.next();
                        System.out.println("s = " + s);
                    }
                }
            }
  • 4、List集合

    • 概述
      • 有序集合(序列),用户可以精确控制列表中每个元素的插入位置,可以通过证书索引访问元素,并搜索元素
      • 与Set集合不同,List集合通常允许重复的元素
    • List集合特点
      • 有序:存储和取出的元素顺序一致
      • 可重复:存储的元素可以重复
    • List集合特有方法
      • add(int index, E element):在集合中的指定位置插入指定的元素
      • remove(int index):删除指定索引处的元素,返回被删除的元素
      • set(int index, E element):修改指定索引处的元素,返回被修改的元素
      • get(int index):返回指定索引处的元素
    • 并发修改异常
      • 产生原因:迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一致
      • 解决方案:用 for 循环,然后用集合对象做对应的操作
    • ListIterator
      • 列表迭代器
        • 通过List集合的listIterator()方法得到,是List集合特有的迭代器
        • 运行沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
      • ListIterator中的常用方法
        • next():返回迭代中的下一个元素
        • hasNext():如果迭代具有更多元素,则返回true
        • previous():返回列表中的上一个元素
        • hasPrevious():如果列表迭代器相反方向遍历时具有更多元素,则返回true
        • add(E e):将指定的元素插入列表
    • 增强 for 循环
      • 概述:
        • 简化数组和Collection集合的遍历
        • 实现Iterable接口的类允许其对象成为增强 for 循环语句的目标
        • JDK5以后出现的,内部原理是一个Iterator迭代器
      • 格式:
        for(元素数据类型 变量名: 数组或者Collection集合) {
            // 此处使用变量即可,该变量就是元素  
        }
    • List集合子类特点
      • List集合常用子类:
        • ArrayList:底层数据结构是数组,查询块,增删慢
          • 常用方法
            • add(E e):在集合末尾添加指定元素
            • add(int index, E element):在集合的指定位置插入指定元素
            • remove(Object o):删除指定的元素,没有则不删除
            • remove(int index):删除指定索引处的元素
            • set(int index, E element):修改指定索引处的元素
            • get(int index):获取指定索引处的元素
            • size():获取集合中的元素个数
              // 1、创建ArrayList集合对象
              ArrayList<String> arr = new ArrayList<String>();
              
              // 2、集合末尾添加元素
              arr.add("hello");
              arr.add("world");
              arr.add("wow");
              System.out.println(arr); // [hello, world, wow]
              
              // 3、集合指定位置添加元素
              arr.add(1,"java");
              System.out.println(arr); // [hello, java, world, wow]
              
              // 4、获取指定位置元素
              System.out.println(arr.get(1)); // java
              
              // 5、删除指定元素
              arr.remove("wow");
              System.out.println(arr); // [hello, java, world]
              
              // 6、删除指定位置元素
              arr.remove(1);
              System.out.println(arr); // [hello, world]
              
              // 7、获取集合中元素个数
              System.out.println(arr.size()); // 2
          • ArrayLis集合遍历(3种方式)
            import java.util.ArrayList;
            import java.util.Iterator;
            
            public class Demo {
                public static void main(String[] args) {
                    // 创建对象
                    ArrayList<String> arr = new ArrayList<String>();
            
                    // 添加元素
                    arr.add("hello");
                    arr.add("world");
                    arr.add("java");
            
                    // 遍历方式一:迭代器
                    Iterator<String> it = arr.iterator();
                    while (it.hasNext()) {
                        String s = it.next();
                        System.out.println("s = " + s);
                    }
                    System.out.println("--------");
            
                    // 遍历方式二:普通for循环
                    for (int i = 0; i < arr.size(); i++) {
                        String s = arr.get(i);
                        System.out.println("s = " + s);
                    }
                    System.out.println("--------");
            
                    // 遍历方式三:增强for循环
                    for (String s : arr) {
                        System.out.println("s = " + s);
                    }
                }
            }
        • LinkedList:底层数据结构是链表,查询慢,增删快
          • LinkedList集合特有方法
            • addFirst(E e):在该列表开头插入指定的元素
            • addLast(E e):将指定的元素追加到此列表末尾
            • getFirst():返回此列表中的第一个元素
            • getLast():返回此列表中的最后一个元素
            • removeFirst():从此列表中删除并返回第一个元素
            • removeLast():从此列表中删除并返回最后一个元素
  • 5、Set集合

    • Set集合特点
      • 不包含重复元素的集合
      • 没有带索引的方法,所以不能使用普通 for 循环
        import java.util.HashSet;
        import java.util.Set;
        
        public class Demo {
            @SuppressWarnings("all")
            public static void main(String[] args){
                // 创建集合对象
                Set<String> s = new HashSet<String>();
                
                // 添加元素
                s.add("hello");
                s.add("world");
                s.add("java");
                // 不包含重复元素
                s.add("world");
                
                // HashSet集合对迭代的顺序不作任何保证
                for (String s1 : s) {
                    System.out.println("s1 = " + s1);
                }
            }
        }
    • 哈希值
      • 哈希值:是 JDK 根据对象的地址或者字符串或者数字算出来的 int 类型的数值
      • Object 类中有一个方法可以获取对象的哈希值
        • hashCode():返回对象的哈希值
      • 对象的哈希值特点:
        • 同一个对象多次调用hashCode()方法,返回的哈希值是相同的
        • 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现不同对象的哈希值相同
    • HashSet集合
      • HashSet集合特点
        • 底层数据结构是哈希表
        • 对集合的迭代顺序不作任何保证
        • 没有带索引的方法,不能使用普通 for 循环
        • 不包含重复元素
      • 如何保证对象的成员变量值相同,就认为是同一个对象?
        • 重写hashCode() 和 equals() 方法---(自动生成即可
    • LinkedHashSet集合
      • LinkedHashSet集合特点
        • 由哈希表和链表实现的Set接口,具有可预测的迭代顺序
        • 由链表保证元素有序
        • 由哈希表保证元素唯一
    • TreeSet集合
      • TreeSet集合特点
        • 元素有序(按照一定的规则,具体排序方式取决于构造方法)
          • TreeSet():根据元素的自然排序进行排序
          • TreeSet(Comparator comparator):根据指定的比较器进行排序
        • 没有带索引的方法,不能使用普通 for 循环
        • 不包含重复元素
      • 自然排序 Comparable 的使用
        • 自然排序,就是让元素所属的类实现 Comparable 接口,重写 compareTo(T o)方法
        • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
          import java.util.TreeSet;
          
          public class Demo {
              @SuppressWarnings("all")
              public static void main(String[] args) {
                  // 创建集合对象
                  TreeSet<Student> s = new TreeSet<Student>();
          
                  // 添加元素
                  s.add(new Student("wangzhaojun", 25));
                  s.add(new Student("diaochan", 29));
                  s.add(new Student("xishi", 27));
                  s.add(new Student("yangyuhuan", 21));
                  // 不包含重复元素
                  s.add(new Student("diaochan", 29));
          
                  // 遍历集合
                  for (Student stu : s) {
                      System.out.println(stu.name + "," + stu.age);
                  }
              }
          }
          
          class Student implements Comparable<Student> {
              public String name;
              public int age;
          
              public Student(String name, int age) {
                  this.name = name;
                  this.age = age;
              }
              
              @Override
              public int compareTo(Student o) {
                  // 按照年龄从小到大排序,如果需要从大到小排序,this 和 o 交换位置即可
                  int num = this.age - o.age;
          
                  // 年龄相同,按照姓名字母顺序排序(String已经实现了compareTo接口)
                  int num2 = num == 0 ? this.name.compareTo(o.name) : num;
                  return num2;
              }
          }
      • 比较器排序 Comparator 的使用
        • TreeSet集合存储自定义对象,带参构造方法使用比较器排序对元素进行排序
        • 比较器排序,就是让集合构造方法接收 Comparator 的实现类对象,重写 compare(T o1, T o2)方法
        • 重写方法时,一定要注意排序规则:先主要条件,再次要条件
          import java.util.Comparator;
          import java.util.TreeSet;
          
          public class Demo {
              @SuppressWarnings("all")
              public static void main(String[] args) {
                  // 创建集合对象(通过匿名内部类的形式传入比较器对象)
                  TreeSet<Student> s = new TreeSet<Student>(new Comparator<Student>() {
                      @Override
                      public int compare(Student s1, Student s2) {
                          // 按照年龄从小到大排序,如果需要从大到小排序,s1 和 s2 交换位置即可
                          int num = s1.age - s2.age;
          
                          // 年龄相同,按照姓名字母顺序排序
                          int num2 = num == 0 ? s1.name.compareTo(s2.name) : num;
                          return num2;
                      }
                  });
          
                  // 添加元素
                  s.add(new Student("wangzhaojun", 25));
                  s.add(new Student("diaochan", 29));
                  s.add(new Student("xishi", 27));
                  s.add(new Student("ruhua", 27));
                  s.add(new Student("yangyuhuan", 21));
                  // 不包含重复元素
                  s.add(new Student("diaochan", 29));
          
                  // 遍历集合
                  for (Student stu : s) {
                      System.out.println(stu.name + "," + stu.age);
                  }
              }
          }
          
          class Student {
              public String name;
              public int age;
          
              public Student(String name, int age) {
                  this.name = name;
                  this.age = age;
              }
          }
  • 6、泛型

    • 概述
      • 本质是参数化类型,也就是说操作的数据类型被指定为一个参数
      • 将类型由原来的具体的类型参数化,然后在使用 / 调用时传入具体的类型
      • 这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口
    • 泛型定义格式
      • <类型>:指定一种类型的格式。这里的类型可以看成是形参,具体调用时,只能是引用数据类型
      • <类型1, 类型2...>:指定多种类型的格式,多种类型之间用逗号隔开
    • 泛型的好处:
      • 把运行时期的问题提前到了编译期间
      • 避免了强制类型转换
    • 泛型类、方法、接口
      • 泛型类:
        • 定义格式:修饰符 class 类名<类型>{ };
        • 范例:public class Generic<T>{ }  
          • 常见的如T、E、K、V等形式的参数常用于表示泛型
      • 泛型方法:
        • 定义格式:修饰符 <类型> 返回值类型 方法名(类型 变量名){ }
        • 范例:public <T> void show(T t){ }
      • 泛型接口
        • 定义格式:修饰符 interface 接口名<类型>{ }
        • 范例:public interface Generic<T>{ }
        • 泛型接口实现类定义格式:修饰符 class 类名<类型> implements 接口名<类型>{ }
        • 泛型接口实现类范例:public class GenericImpl<T> implements Generic<T>{ } 
      • 示例
        public class Demo {
            @SuppressWarnings("all")
            public static void main(String[] args) {
                // 泛型类测试
                Generic<String> g1 = new Generic<String>();
                g1.show("100");
                Generic<Integer> g2 = new Generic<Integer>();
                g2.show(100);
                Generic<Boolean> g3 = new Generic<Boolean>();
                g3.show(true);
        
                // 泛型方法测试
                Generic2 gg1 = new Generic2();
                gg1.show("100");
                gg1.show(100);
                gg1.show(true);
        
                // 泛型接口测试
                GenericImpl<String> ggg1 = new GenericImpl<String>();
                ggg1.show("100");
        
                GenericImpl<Integer> ggg2 = new GenericImpl<Integer>();
                ggg2.show(100);
        
                GenericImpl<Boolean> ggg3 = new GenericImpl<Boolean>();
                ggg3.show(true);
            }
        }
        
        // 泛型类
        class Generic<T>{
            public void show(T t){
                System.out.println("t = " + t);
            };
        }
        
        // 泛型方法
        class Generic2{
            public <T> void show(T tt){
                System.out.println("tt = " + tt);
            }
        }
        
        // 泛型接口
        interface Generic3<T>{
            void show(T t);
        }
        
        // 泛型接口实现类
        class GenericImpl<T> implements Generic3<T>{
            @Override
            public void show(T ttt) {
                System.out.println("ttt = " + ttt);
            }
        }
    • 类型通配符
      • 任意类型通配符:<?>
        • List<?>:元素类型未知的List
        • 示例:List<?> list = new ArrayList<Object>()
      • 类型通配符上限:<? extends 类型>
        • List<? extends Number>:Number或者其子类型
        • 示例:List<? extends Number> list = new ArrayList<Integer>()
      • 类型通配符下限:<? super 类型>
        • List<? super Number>:Number或者其父类型
        • 示例:List<? super Number> list = new ArrayList<Object>()
    • 可变参数
      • 格式:修饰符 返回值类型 方法名(数据类型... 变量名)
      • 范例:public static int sum(int... a){ }
      • 注意事项:
        • 这里的变量其实是一个数组
        • 如果一个方法有多个参数,包含可变参数,可变参数要放在最后
  • 7、Map集合

    • 概述
      • interface Map<K, V>       K:键的类型,V:值的类型
      • 将键映射到值的对象;不能包含重复的键;每个键映射到最多一个值
    • 创建Map集合的对象
      • 多态的方式
      • 具体的实现类 HashMap
    • Map集合常用方法:
      • V put(K key, V value):添加元素
      • V get(Object key):根据键获取值
      • Set<K> keySet():获取所有键的集合
      • Collection<V> values():获取所有值的集合
      • V remove(Object key):根据键删除键值对元素
      • Set<Map.Entry<K, V>> entrySet():获取所有键值对对象的集合
      • void clear():移除所有的键值对元素
      • boolean containsKey(Object key):判断集合是否包含指定的键
      • boolean containsValue(Object value):判断集合是否包含指定的值
      • boolean isEmpty():判断集合是否为空
      • int size():集合的长度,也就是集合中键值对的个数
    • Map集合的遍历
      • 方式一:先获取所有键的集合,然后根据键,获取相应值
      • 方式二:先获取所有键值对对象的集合,然后根据单个对象获取其键、值

        import java.util.HashMap;
        import java.util.Map;
        import java.util.Set;
        
        public class Demo {
            @SuppressWarnings("all")
            public static void main(String[] args) {
                // 创建Map集合对象
                Map<String, String> m = new HashMap<String, String>();
        
                // 添加元素
                m.put("林青霞", "北京");
                m.put("王祖贤", "上海");
                m.put("张曼玉", "重庆");
                m.put("周慧敏", "天津");
                m.put("小龙女", "成都");
                m.put("小辣椒", "武汉");
        
                // 判断集合是否为空
                System.out.println(m.isEmpty());
        
                // 输出集合
                System.out.println("m = " + m);
        
                // 输出集合大小
                System.out.println(m.size());
        
                // 根据键获取值
                System.out.println(m.get("林青霞"));
        
                // 判断键是否存在
                System.out.println(m.containsKey("小龙女"));
                System.out.println(m.containsKey("如花"));
        
                // 判断值是否存在
                System.out.println(m.containsValue("武汉"));
                System.out.println(m.containsValue("大连"));
        
                // 获取所有键的集合
                System.out.println(m.keySet());
        
                // 获取所有值的集合
                System.out.println(m.values());
        
                // 遍历方式一:
                // 先获取所有键的集合,遍历键,获取相应值
                Set<String> keySet = m.keySet();
                // 遍历键的集合
                for (String s : keySet) {
                    // 根据键,获取相应的值
                    String v = m.get(s);
                    System.out.println(s + "," + v);
                }
        
                // 遍历方式二:
                // 先获取所有键值对对象的集合,然后遍历该集合,然后根据对象,通过getKey()和getValue()方法获取每个对象的键和值
                Set<Map.Entry<String, String>> entries = m.entrySet();
                // 遍历键值对对象集合
                for (Map.Entry<String, String> entry : entries) {
                    // 获取单个对象的键
                    String k = entry.getKey();
                    // 获取单个对象的值
                    String v = entry.getValue();
                    System.out.println(k + "," + v);
                }
            }
        }
  • 8、Collections

    • 概述
      • 针对集合操作类的工具类
    • Collections类的常用方法
      • public static <T extends Comparable<? super T>> void sort(List<T> list):将指定的列表按升序排序
      • public static void reverse(List<?> list):反转指定列表中元素的顺序
      • public static void shuffle(List<?> list):使用默认的随机源随机排列指定的列表
        import java.util.ArrayList;
        import java.util.Collections;
        import java.util.List;
        
        public class Demo {
            @SuppressWarnings("all")
            public static void main(String[] args) {
                // 创建列表对象
                List<Integer> list = new ArrayList<Integer>();
        
                //向列表中添加元素
                list.add(30);
                list.add(20);
                list.add(50);
                list.add(10);
                list.add(40);
        
                // 升序排序
                Collections.sort(list);
                System.out.println(list);
        
                // 反转
                Collections.reverse(list);
                System.out.println(list);
        
                // 随机排
                Collections.shuffle(list);
                System.out.println(list);
            }
        }

十四、反射

  • 1、概述

    • Java反射机制:是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。这种动态性,极大的增强程序的灵活性,不用在编译期就完成确定,在运行期仍然可以扩展
  • 2、获取 Class 类的对象

    • 如果想通过反射去使用一个类,首先要获取到该类的字节码文件对象,也就是类型为Class 类型的对象
    • 三种方式:
      • 使用类的 class 属性
        • 基本数据类型,也可以通过.class属性得到对应的Class对象,比如int.class
        • 示例:Student.class 会返回Student 类对应的 Class对象 
      • 调用对象的getClass()方法
        • Object 类中的方法,所有对象都可以调用
      • 使用Class类中的静态方法forName(String className),需要传入类的全路径(含完整包名)
  • 3、反射获取构造方法并使用

    • Class类中用于获取构造方法对象的方法
      • Constructor<?>[] getConstructors():返回所有公有构造方法的数组
      • Constructor<T> getConstructor(Class<?>... parameterTypes):返回单个公有构造方法对象,参数为数据类型对应的字节码文件对象(比如:int.class)
      • Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
      • Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回单个构造方法对象
    • Constructor类中用于创建对象的方法
      • T newInstance(Object... initargs):根据指定的构造方法创建对象
      • public void setAccessible(boolean flag):值为true,取消访问检查(暴力反射,可以访问私有构造方法)
        package com.java.app;
        
        import java.lang.reflect.Constructor;
        import java.lang.reflect.InvocationTargetException;
        
        public class Demo {
            @SuppressWarnings("all")
            public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
                // 获取Class对象
                Class<?> c = Class.forName("com.java.app.Student");
        
                // 获取并遍历所有公有构造方法的数组
                Constructor<?>[] constructors = c.getConstructors();
                for (Constructor<?> constructor : constructors) {
                    System.out.println(constructor);
                }
                System.out.println("------------");
        
                // 获取并遍历所有构造方法的数组
                Constructor<?>[] declaredConstructors = c.getDeclaredConstructors();
                for (Constructor<?> declaredConstructor : declaredConstructors) {
                    System.out.println(declaredConstructor);
                }
                System.out.println("------------");
        
                // 获取单个公有构造方法对象
                Constructor<?> constructor = c.getConstructor();
                // 通过无参构造方法创建对象
                Object o = constructor.newInstance();
                System.out.println(o);
                System.out.println("------------");
        
                // 获取带3个参数的构造方法
                Constructor<?> declaredConstructor2 = c.getDeclaredConstructor(String.class, String.class, int.class);
                // 暴力反射
                declaredConstructor2.setAccessible(true);// 值为true,取消访问检查
                // 通过带参构造方法创建对象
                Object o2 = declaredConstructor2.newInstance("张曼玉", "女", 30);
                System.out.println(o2);
            }
        }
        
        class Student {
            private String name;
            String gender;
            public int age;
        
            public Student() {
            }
        
            Student(String name, String gender) {
                this.name = name;
                this.gender = gender;
            }
        
            private Student(String name, String gender, int age) {
                this.name = name;
                this.gender = gender;
                this.age = age;
            }
        
            @Override
            public String toString() {
                return "Student{" +
                        "name='" + name + '\'' +
                        ", gender='" + gender + '\'' +
                        ", age=" + age +
                        '}';
            }
        }
  • 4、反射获取成员变量并使用

    • Class 类中获取成员变量的方法
      • Field[] getFields():返回所有公有成员变量对象的数组
      • Field[] getField(String name):返回单个公有成员变量对象
      • Field[] getDeclaredFields():返回所有成员变量的数组
      • Field[] getDeclaredField(String name):返回单个成员变量对象
    • Field 类中用于给成员变量赋值的方法
      • Void set(Object obj, Object value):给obj对象的成员变量赋值value
        package com.java.app;
        
        import java.lang.reflect.Constructor;
        import java.lang.reflect.Field;
        import java.lang.reflect.InvocationTargetException;
        
        public class Demo {
            @SuppressWarnings("all")
            public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
                // 获取Class对象
                Class<?> c = Class.forName("com.java.app.Student");
        
                // 获取Field对象
                Field name = c.getDeclaredField("name");
                name.setAccessible(true);
        
                Field age = c.getDeclaredField("age");
                age.setAccessible(true);
        
                // 获取无参构造器对象
                Constructor<?> declaredConstructor = c.getDeclaredConstructor();
                Object o = declaredConstructor.newInstance();
        
                // 设置属性值
                name.set(o, "张曼玉");
                age.set(o, 30);
        
                // 读取属性值
                System.out.println(name.get(o));
                System.out.println(age.get(o));
        
                System.out.println(o);
            }
        }
        
        class Student {
            private String name;
            String gender;
            public int age;
        
            public Student() {
            }
        
            Student(String name, String gender) {
                this.name = name;
                this.gender = gender;
            }
        
            private Student(String name, String gender, int age) {
                this.name = name;
                this.gender = gender;
                this.age = age;
            }
        
            @Override
            public String toString() {
                return "Student{" +
                        "name='" + name + '\'' +
                        ", gender='" + gender + '\'' +
                        ", age=" + age +
                        '}';
            }
        }
  • 5、反射获取成员方法并使用

    • Class 类中用于获取成员方法的方法
      • Method[] getMethods():返回所有公有成员方法对象的数组,包括继承的
      • Method[] getMethod(String name, Class<?>... parameterTypes):返回单个公有成员方法对象
      • Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
      • Method[] getDeclaredMethod(String name, Class<?>... parameterTypes):返回单个成员方法对象
    • Method类中用于调用成员方法的方法
      • Object invoke(Object obj, Object... args):调用obj对象的成员方法,参数时args,返回值是obj类型
        package com.java.app;
        
        import java.lang.reflect.Constructor;
        import java.lang.reflect.InvocationTargetException;
        import java.lang.reflect.Method;
        
        public class Demo {
            @SuppressWarnings("all")
            public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
                // 获取Class对象
                Class<?> c = Class.forName("com.java.app.Student");
        
                // 获取无参构造器对象
                Constructor<?> declaredConstructor = c.getDeclaredConstructor();
                Object o = declaredConstructor.newInstance();
        
                // 调用无参方法:method1()
                Method method1 = c.getDeclaredMethod("method1");
                method1.setAccessible(true); // 取消访问检查
                method1.invoke(o);
        
                // 调用带参数方法:method2()
                Method method2 = c.getDeclaredMethod("method2", String.class);
                method2.invoke(o, "java");
        
                // 调用带参、有返回值方法:method3()
                Method method3 = c.getDeclaredMethod("method3", String.class, int.class);
                Object obj = method3.invoke(o, "java", 100);
                System.out.println(obj);
            }
        }
        
        class Student {
            public Student() {
            }
        
            private void method1() {
                System.out.println("method1");
            }
        
            public void method2(String s) {
                System.out.println("method2: " + s);
            }
        
            public String method3(String s, int i) {
                return "method3: " + s + "--" + i;
            }
        }
  • 6、反射练习--越过泛型检查

    package com.java.app;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    
    public class Demo {
        @SuppressWarnings("all")
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
            // 创建一个集合对象
            ArrayList<Integer> arr = new ArrayList<Integer>();
    
            // 获取Class对象
            Class<?> c = ArrayList.class;
    
            // 获取method对象,通过Object.class绕过泛型检查
            Method m = c.getMethod("add", Object.class);
            
            // 调用add方法,添加String类型的元素
            m.invoke(arr, "hello");
            m.invoke(arr, "world");
            m.invoke(arr, "java");
            System.out.println(arr);
        }
    }

    获取方法对象时,传入Object.class是关键

  • 7、反射练习--运行配置文件指定内容

    package com.java.app;
    
    import jdk.jfr.events.FileReadEvent;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.Properties;
    
    public class Demo {
        @SuppressWarnings("all")
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException {
    
            // 加载配置文件数据
            Properties prop = new Properties();
            FileReader fr = new FileReader("E:\\ProgramFiles\\java_project\\Hello\\class.txt");
            prop.load(fr);
            fr.close();
    
            // 根据键获取值
            String className = prop.getProperty("className");
            String methodName = prop.getProperty("methodName");
    
            // 根据配置文件获取指定的Class对象
            Class<?> c = Class.forName(className);
    
            // 创建对象
            Constructor<?> declaredConstructor = c.getDeclaredConstructor();
            Object o = declaredConstructor.newInstance();
    
            // 调用配置文件中指定的方法
            Method method = c.getMethod(methodName);
            method.invoke(o);
        }
    }
posted @ 2022-11-22 04:56  eliwang  阅读(22)  评论(0编辑  收藏  举报