2021.03.20-JavaSE基础部分

2021.03.20-JavaSE基础部分,第1张

2021.03.20-JavaSE基础部分

 目录

一、初识Java

1、Java的历史和特点

二、Java基本语法

1、数据类型

2、常量与变量

3、类型转化

4、运算符

5、语法结构

6、数组

三、面向对象

1、面向对象初识

2、方法设计

3、类的结构

4、类和类的关系

5、修饰符

6、类的加载

7、面向对象四大特性

8、内部类

9、枚举

四、工具类

1、包装类

2、与数学相关的类

3、与日期相关的类

4、String类

5、正则表达式

6、JDK8新的日期类

五、集合

1、List

2、Queue接口

3、Set

4、Map

六、异常

1、错误error

2、Exception异常

3、处理异常

4、Throws抛出

5、自定义异常

6、开发中如何选择


一、初识Java 1、Java的历史和特点

1.1、历史

1.2、特点

  • *1.跨平台性 平台(不同厂商的芯片) 平台(不同版本的 *** 作系统)

  • *2.面向对象

  • 3.简单性 省去了C++多继承,指针等等

  • 4.健壮性(鲁棒性) 垃圾回收机制 异常处理机制

  • 5.多线程性 并行 *** 作 提高执行性能 线程安全

  • 6.大数据开发

1.3、跨平台机制

  • JVM Java Virtual Machine虚拟机

    • 内存中开辟一块空间 源文件 编译 字节码

  • JRE Java Runtime Environment 运行环境

    • 运行别人写好的java程序

    • JDK安装中间产生一个安装JRE

  • JDK Java Development Kit 开发工具包

    • 开发时需要用到的工具 javac.exe 编译工具 java.exe 执行工具 底层doc命令窗口中看到效果

1.4、编译与执行

1、命名规约

  • 名字中可以含有如下的信息 字母(区分大小写 敏感 52个) 数字(0-9 可以用 不能用作开头) 符号(英文 _ $) 中文(强烈不推荐---当做不行)

  • 类名字 首字母大写TestOne 如果两个以上的单词 每个单词的首字母都大写

  • 变量名 首字母小写 如果两个以上的单词 之后的首字母大写 superPerson 遵循驼峰式命名规约

  • 起名字要见名知义 建议大家尽量使用英文单词

2、编译执行

  • javac Test.java

  • java Demo

二、Java基本语法 1、数据类型

1.1、基本类型

  • 基本数据类型 8个

  • 4整型 byte(1字节) short(2字节) int(4字节) long64(8字节)

  • 2浮点型 float 32(4字节) double 64(8字节)

  • 1字符型 char 16bit (2字节) Unicode编码 0-65535

  • 1布尔型 boolean (1bit) true false

1.2、引用数据类型

  • 数组[]

  • 类class(抽象类abstract class)

  • 接口interface

  • 枚举enum

  • 注解

2、常量与变量

2.1、常量

常量 常量代表是程序运行过程中 不能再次改变的值 常量的作用 1.固定的值 代表计算过程中经常用到的值 便于程序计算 圆周率 3.1415926..... 2.用来代表一个含义 UP==>1 2 3 4分别代表 上下左右四个方向 什么样的值算是常量??? 1.固定不变的值 算作常量,1 3.14 'a' true 可以认为所有基本类型的值 固定不变 是常量 2.特殊的常量 "abc"--->String String是一个引用数据类型,它的值很特殊 可以简单的视为常量 3.自己创建的空间 存储一个值 让他固定起来 不能改变 final int UP = 1;

2.2、变量

1、说明

  • 变量指的是 程序执行过程中可以改变的

  • 变量是一个内存空间(小容器)

  • 变量空间在创建(声明)的时候 必须指定数据类型 变量空间的名字

  • 变量空间 里面只能存储一个内容(值 引用)

  • 变量空间内的内容可以改变

  • 注意:

    变量是一个空间 可以只创建空间 里面不存放内容 ​ 变量空间创建后是没有默认的内容 空的 ​ 空的变量空间不能拿来使用 编译错误

3、类型转化

3.1、同种数据类型

  • 同种数据类型之间可以直接进行赋值 *** 作

    • int a = 1;int b = a;

    • float x = 3.4;float y = x;

3.2、不同数据类型

1、基本类型与基本类型

  • 可以直接转换(自动 强制)

1.1、都是整数或都是浮点数

  • 大空间变量可以直接存储小空间的数据

  • 小空间变量不可以直接存储大空间的数据(需要强制类型转换)

  • byte a = 1; int b = a;//自动直接转化就可以 int a = 1; byte b = (byte)a;//需要强制类型转换 float x = 3.4F; double y = x;//自动直接转化 double x = 3.4; float y = (float)x;//强制转换

1.2、小数据类型不同

  • 整型---浮点型

    两个比较精确程度 浮点型精确程度更高 可以直接存放整数 反之需要强制转换

    • int a = 1; float b = a;//自动直接转化

    • float a =1.0F; int b = (int)a;//强制类型转换

  • 整型---字符型

    • char x = 'a'; int y = x;//自动转化 y--97

    • int x = 97; char y = (char)x;//强制的转化

  • 布尔类型很特殊,不能与其他基本类型之间发生转化

2、引用类型与引用类型

  • 可以直接转换(自动 强制--上转型 下转型)

3、基本类型与引用类型

  • 不可以直接转换(间接--包装类/封装类)

4、运算符
  • 运算符 用来指明对于 *** 作数的运算方式

4.1、分类

1、按照 *** 作数的数目来进行分类

  • 单目:a++

  • 双目:a+b

  • 三目:(a>b)?x:y;

2、按照运算符的功能来进行分类

  • +,-,/, %(取余 取模)

  • ++(自增) --(自减)

    • x在想要做值交换的时候 会产生一个临时的副本空间(备份)

    • ++在变量的前面 先自增后备份 ++在变量的后面 先备份后自增

    • 最后会将副本空间内的值赋给别人

3、针对x=x++问题

当执行这句时, 1,java先运算x++这个表达式,并将结果存储在一个空间中,这里我们假设这个空间名字为tmp,于是此时tmp=0, 2,然后自加生效,对x自加,这时x=1, 3,接着java执行x=这一赋值部分,因为x++运算的结果是存储在tmp中的,所以实际上是x=tmp,所以x又变为了0

4.2、变量的赋值

4.3、运算

1、关系运算

  • ,>,>=,= < <= != == (对象 instanceof 类)

2、逻辑运算

  • &(逻辑与)、|(逻辑或)

  • ^:(3>1) ^ (3>2) 为false,前后两个结果不一致为true

  • !:!(3>2)为false

  • &&(短路与)、||(短路或):(3>2) && (3>1),前面执行失败,后面的就不执行了

3、位运算

  • &:按位与,即只有两个都为1,结果才为1,其他为0

  • |:按位或,即两个中只要有一个1,结果就为1,其他为0

  • ^:按位异或,即只有两个数不同0、1时,结果才为1,其他为0

  • ~:按位取反

  • <<:按位左移,2<<1的值为4,即2*(2^1)

  • ,>>:按位右移,2>>1的值为1,即2/(2^1)

4、优先级

5、语法结构

6、数组

6.1、特点

  • 1.数组本身是一个引用数据类型

  • 2.数组是在堆内存中的一串连续的地址存在

  • 3.数组在初始化时必须指定长度

  • 4.堆内存的数组空间长度一旦确定 不能再次发生改变

  • 5.栈内存的变量中存储的是数组的地址引用

  • 6.数组内部存储的类型可以是基本的 也可以是引用

6.2、使用

1、数组的定义

数据类型[] 数组名字; int[] x; char[] y; boolean[] z; String[] m;

2、数组的赋值(初始化)

  • 静态初始化,有长度 有元素

    • int[] array = {10,20,30,40,50};

    • int[] array = new int[]{10,20,30};

  • 动态初始化, 有长度 没有元素(不是真的没有 默认值)

    • int[] array = new int[5];

      整数默认值---0 浮点数默认值---0.0 字符型默认值--- 0---char 97-a 65-A 48-'0' 布尔型默认值--- false 引用数据默认值--- null String[]

3、遍历

  • 普通for循环

    • 特点:

      • 可以通过index直接访问数组的某一个位置 存值 取值都可以

      • 不好在于写法相对来说比较麻烦

  • 增强for(forEach)

    • 特点

      • 没有index索引

      • 好处写法相对比较容易

      • 不好只能取值 不能存值

      • 没有index索引 找不到元素到底是哪一个

4、基本数据类型和引用数据类型在内存结构上的区别

  • 所有的变量空间都存储在栈内存

  • 变量空间可以存储基本数据类型 ,也可以存储引用数据类型

  • 如果变量空间存储的是基本数据类型 ,存储的是值 ,一个变量的值改变 另一个不会跟着改变

  • 如果变量空间存储的是引用数据类型 ,存储的是引用(地址), 一个变量地址对应的值改变 ,另一个跟着改变

5、传参的区别

内存图解释

  • 基本数据类型的传参

  • 引用类型的传参

6.3、二维数组

  • 内存结构

三、面向对象 1、面向对象初识
  • 类的加载及对象的创建

2、方法设计

2.1、方法书写要求

  • 权限修饰符 [特征修饰符] 返回值类型 方法名字 (参数列表) [抛出异常] [{ 方法体 }]

    • 权限修饰符:public、protected、private、默认

    • 特征修饰符:static、final、abstract

    • 返回值:String、Object...

2.2、方法参数和返回值

1、数组互换

  • 方法一

  • 方法二

2.3、方法重载

1、概念

  • 一个类中的一组方法 相同的方法名字 不同的参数列表 这样的一组方法构成了方法重载

    • 参数个数

    • 参数类型

2、作用

  • 为了让使用者便于记忆与调用 只需要记录一个名字 执行不同的 *** 作

3、动态参数列表

  • JDK1.5版本 之后出现的

  • int... x ,个数可以动态0--n都可以

  • x本质就是一个数组,有length属性,有[index]

  • 动态参数列表必须方法参数的最后,一个方法最多只能有一个。

3、类的结构

3.1、内部成员

  • 1.属性---静态描述类的特征(变量 存值) name

  • 2.方法---动态描述类的行为(做事情) eat

  • 3.构造方法---用来创建当前类的对象(方法 很特殊)

  • 4.程序块(代码块)---理解为就是一个方法(非常特殊的 无修饰符无参数无返回值无名字)

3.2、构造方法

1、作用

  • 只有一个 构建(构造)当前类的对象

2、写法

权限修饰符 与类名一致的方法名 (参数列表) [抛出异常]{ ​ ​ }

3、特点

  • 存在构造方法重载

3.2、代码块

1、作用

  • 跟普通方法一样 做事情的

2、写法

{

}

3、用法

  • 块也需要调用才能执行 我们自己调用不到(没有名字),每一次我们调用构造方法之前 , 系统会帮我们自动的调用一次程序块 ,让他执行一遍

  • 可以在类中定义多个程序块

  • 可以被static修饰

4、类和类的关系

4.1、继承 is-a

  • 1.子类继承父类,通过一个关键字 extends

  • 2.子类的对象可以调用父类中的(public protected)属性和方法 当做自己的来使用

  • 3.子类可以添加自己独有的属性和方法的

  • 4.子类从父类中继承过来的方法不能满足子类需要,可以在子类中重写(覆盖)父类的方法 更多指的是内容

  • 5.每一个类都有继承类,如果不写extends关键字,默认继承Object,如果写了extends则继承后面那个父类 可以理解为Object类非常重要 是任何一个引用类型的父类(直接或间接的继承Object) Object类没有父类

  • 6.Java中继承是单个存在的(单继承) 每一个类只能有一个继承类 (在extends关键字后面只能写一个类) 可以通过传递的方式实现多继承的效果 后续还会有多实现

  • *7.继承在内存中的存储形式

    • 这个图有问题,但有利于我们理解

  • *8.关于this和super的使用

4.2、Object类

  • hashCode() 将对象在内存中的地址经过计算得到一个int整数 public native int hashCode();

  • equals() 用来比较两个对象的内容 Object默认效果是==。 ==可以比较基本类型(比较值) 可以比较引用类型(比较地址) equals方法时Object类中继承过来的方法 默认效果比较地址 如果想要改变其规则 可以进行方法重写 public boolean equals(Object obj){ return (this == obj); }

  • toString() 打印输出时将对象变成String字符串 public String toString(){ return this.getClass().getName()+"@"+Integer.toHexString(this.hashCode()); }

  • getClass() 获取对象对应类的类映射(反射)

  • wait() 线程进入挂起等待状态 存在方法重载

  • notify() 线程唤醒

  • notifyAll() 唤醒所有

  • finalize() 权限修饰符是protected 在对象被GC回收的时候 默认调用执行的方法 final finally finalize区别 protected void finalize(){

}

  • clone() 权限修饰符是protected 为了克隆对象

4.3、包含(聚合) has-a

  • 通过一个类的对象当做另一个类的属性类存储

public class User{
   private Dog dog;
}

4.4、依赖 use-a

  • 一个类的方法中使用到了另一个类的对象

    • 可以在方法中传递参数

    • 也可以在方法中自己创建

public class User{
    public void method(Dog dog){
        dog.eat();
    }
    
    public void method2(){
        Dog dog = new Dog();
    }
}
  • 设计类的关系遵循的原则:高内聚,低耦合 耦合度: 紧密 继承(实现) > 包含 > 依赖

5、修饰符

5.1、权限修饰符

1、修饰类

  • 普通类只能被public、abstract、final修饰

  • 内部类可以被public、默认、private、protected、abstract、final修饰

2、修饰成员

5.2、特征修饰符

1、final

1.1、修饰变量

  • 变量就是方法里面定义的值

  • 如果在定义变量时没有赋初始值

  • 给变量一次存值的机会(因为变量在栈内存空间内, 没有默认值 如果不给机会 就没法用啦)

  • 一旦变量被存储了一个值 若用final修饰后, 则不让再次改变 ----> 相当于常量啦(值没法动)

  • 注意变量类型是基本类型还是引用类型

  • 如果修饰的变量是基本数据类型 ,则变量内的值不让更改---常量

  • 如果修饰的变量是引用数据类型, 则变量内的地址引用不让更改---对象唯一

1.2、修饰属性

  • 全局变量 存储在堆内存的对象空间内一个空间

  • 属性如果没有赋值 有默认值存在的

  • 属性用final修饰后 必须给属性赋初值 否则编译报错

  • 特点与修饰变量一致

  • 注意变量类型是基本类型还是引用类型

  • 如果修饰的变量是基本数据类型 则变量内的值不让更改---常量

  • 如果修饰的变量是引用数据类型 则变量内的地址引用不让更改---对象唯一

1.3、修饰方法

  • 方法是最终的方法 不可更改

  • 子类继承父类的方法 将父类的方法重写(覆盖)

  • final修饰的方法 要求不可以被子类重写(覆盖)

1.4、修饰类本身

  • 类是最终的 不可以更改

  • (太监类 无后) 此类不可以被其他子类继承

  • 通常都是一些定义好的工具类

    • Math Scanner Integer String

2、static

  • 可以修饰 : 修饰属性 修饰方法 *修饰块 修饰类(内部类)

特点:

  • 1.静态元素在类加载时就初始化啦,创建的非常早,此时没有创建对象

  • 2.静态元素存储在静态元素区中,每一个类有一个自己的区域,与别的类不冲突

  • 3.静态元素只加载一次(只有一份),全部类对象及类本身共享

  • 4.由于静态元素区加载的时候,有可能没有创建对象,可以通过类名字直接访问

  • 5.可以理解为静态元素不属于任何一个对象,属于类的

  • 6.静态元素区Garbage Collection无法管理,可以粗暴的认为常驻内存

  • 7.非静态成员(堆内存对象里)中可以访问静态成员(静态区)

  • 8.静态成员中可以访问静态成员(都存在静态区)

  • 9.静态成员中不可以访问非静态成员(个数 一个出发访问一堆相同名字的东西 说不清)(静态元素属于类 非静态成员属于对象自己)

  • 10.静态元素中不可以出现this或super关键字(静态元素属于类)

  • 静态方法存在于方法区中的静态区,当被调用时,在栈中加载并执行,执行完成后,就d栈结束。事实上,所有的方法都在栈中加载。

3、abstract

  • 可以修饰:类、方法

3.1、特点

  • 抽象类中必须有抽象方法么? 不是必须含有抽象方法

  • 抽象方法必须放在抽象类中么? 目前来看必须放在抽象类中(或接口中) 普通类是不允许含有抽象方法

3.2、成员

  • 属性 可以含有一般的属性 也可以含有 private static final等等

  • 方法 可以含有一般的方法 也可以含有 private static final等等

    • 注意:抽象类中是允许含有抽象方法(只有方法结构 没有方法执行体)

  • 块 可以含有一般的程序块 也可以含有static程序块

  • 构造方法 可以含有构造方法 包括重载

3.3、继承关系

  • 抽象类----直接单继承----抽象类 可以

  • 抽象类----直接单继承----具体类 可以 (用法通常不会出现)

  • 具体类----直接单继承----抽象类 不可以 (需要将父类的抽象方法具体化 或子类也变成抽象类)

5.3、接口

1、简述

  • 通常是为了定义规则

  • 接口也是一个类的结构 只不过 用interface修饰 替换原有的class

2、成员

  • 属性 不能含有一般属性 只能含有公有的静态的常量 public static final

  • 方法 不能含有一般方法 只能含有公有的抽象的方法(1.8 defualt修饰具体方法)

  • 块 不能含有一般程序块 也不能含有static块(块本身就是具体的 接口中不让有具体的)

  • 构造方法 不能含有构造方法

3、与类的关系

  • 接口不能继承别的类 最抽象

  • 抽象类----直接多实现----接口 可以

  • 具体类----直接多实现----接口 不可以(必须将接口中的抽象方法具体化 ,或者自己变成抽象类)

  • *接口---多继承---接口 可以直接多实现,这里用extends(继承)

6、类的加载

存在继承关系的类 加载机制 及执行过程 加载类的过程---静态元素已经加载 new Person(); 1.加载父类 2.父类会产生自己的静态空间 属性 方法 块 执行静态块 3.加载子类 4.子类会产生自己的静态空间 属性 方法 块 执行静态块 5.开辟对象空间 6.加载父类的非静态成员 属性 方法 块 构造方法 7. 执行块 执行父类构造方法 8. .加载子类的非静态成员 属性 方法 块 构造方法 9. 执行块 执行子类构造方法 10. 将对象空间的地址引用交给 变量来存储

7、面向对象四大特性
  • 继承、封装、多态、(抽象)

7.1、多态

  • 同一个对象 体现出来的多种不同形态(身份) 将一种行为表现出不同的效果

  • 要想实现多态的效果 需要现有继承关系

8、内部类

8.1、成员内部类

1、定义

  • 将一个类直接定义在类的里面,作为成员,与属性或方法层次一致

  • 成员内部类可以与正常类一样 使用不同的修饰符来修饰

2、好处

  • 1.省略了一个.java文件

  • 2.成员内部类中可以访问外部类的所有成员 包括私有的

3、使用方法

  • 创建非静态内部类:InnerDemo innerDemo = demo.new InnerDemo();

  • 创建静态内部类:Demo.InnerDemoStatic ids = new Demo.InnerDemoStatic();

  • 注意:

    • 创建了内部类对象后,只能调用内部类里面的方法和属性,不能调用外部的方法和属性

    • 但内部类里面定义的方法,可以访问外部的所有成员。

public static void main(String[] args){
        //内部类属于外部类的(相当于是一个成员) 需要外部类对象才能 *** 作
        //创建内部类的对象---调用内部类的方法
        Demo demo = new Demo();
        InnerDemo innerDemo = demo.new InnerDemo();
        //调用内部类的方法
        innerDemo.testInnerDemo();
​
        //静态的成员内部类
        Demo.InnerDemoStatic ids = new Demo.InnerDemoStatic();
    }
public class Demo {
    private String name = "这是正常类中的属性";
    public void testDemo(){
        System.out.println("这是正常类中的方法");
    }
    public void testDemoOne(){
        String s = "";
        //定义一个局部内部类
        class InnerTestMethod{
            //局部内部类中使用的局部变量都需要加final修饰
        }
    }
    public void testDemoTwo(){
        String s;
        //定义一个局部内部类
        class InnerTestMethod{
​
        }
    }
​
    //成员内部类
    public class InnerDemo{
        private String name="我是内部类的属性";
        public void testInnerDemo(){
            System.out.println("我是成员内部类的方法:"+this.name);//输入的是“我是内部类的属性”
            Demo.this.testDemo();
        }
    }
​
    private static class InnerDemoStatic{
​
    }
​
}
​

8.2、局部内部类

1、简介

  • 将一个类定义在方法/块里面,作为成员的内部结构,与临时的局部变量一个层次

  • 局部内部类像是一个局部的变量一样,不能用public protected private及static,只能用abstract或final

  • 局部内部类命名规则Demo$1InnerTestMethod Demo$2InnerTestMethod

  • 局部内部类使用的变量只能是final修饰

8.3、匿名内部类

1、分类

  • 成员匿名内部类:在属性上面

  • 局部匿名内部类:在方法里面

2、书写

public interface Test{
    public void test();
}
​
public class Demo{
    //成员匿名内部类
    private Test test = new Test(){
        @Override
        public void test(){
            
        }
    }
}

3、特点

  • 通常接口或抽象类的具体子类这样写

  • 开发中为了省略一个类文件 上述写法比较常见

  • 匿名内部类很特殊 只有类体 没有类的所有结构( 修饰符 名字 继承 实现)

  • 不能用任何修饰符来修饰 匿名内部类也没有构造方法

8.4、静态内部类

  • 成员静态内部类

  • 不需要外部类对象,通过正常的方式直接创建内部类

  • 静态元素不能访问非静态成员(自己类和外部类)

9、枚举

9.1、简介

  • 一个类中的对象 认为个数是有限且固定的 可以将每一个对象一一列举出来

9.2、定义

  • 我们自己定义的enum类型直接默认继承Enum(java.lang包)

  • 我们自己定义的enum类型不能再写extends 但是可以实现

9.3、Enum类型

1、属性

  • name----->枚举对象的名字 name()获取name属性

  • ordinal--->枚举对象在类中罗列的顺序 类似index 也从0开始 ordinal()获取序号

2、方法

  • valueOf() 通过给定的name获取对应的枚举对象

  • values() 获取全部的枚举对象 ---> 返回一个数组 Day[]

  • compareTo() 可以比较两个枚举对象 int

  • toString() 由于这个方法没有final修饰 可以覆盖(重写)

3、特点

  • 必须在enum类中第一行 描述一下枚举的样子 最后需要分号结束;

  • 可以定义自己的属性

  • 类创建的过程中 帮我们创建枚举类型的对象

  • 需要给枚举类型提供对应样子的构造方法 构造方法只能private修饰 可以重载

4、使用

public enum Day {
    monday,tuesday,wednesday,thursday,friday,saturday,sunday;
    //和单例模式有些像
    //public static final Day monday=new Day();
    //static是让对象只创建一次,final是让对象不能再更改
    public void test(){
        System.out.println("测试一下");
        //monday.name();
    }
}

public class Test {
    public static void main(String[] args) {
        Day d = Day.monday;
        d.test();
        System.out.println(d.name()+"--"+d.ordinal()+d.valueOf("tuesday"));
    }
}
四、工具类

1、包装类

1.1、分类

  • byte---Byte

  • short---Short

  • int---Integer

  • long---Long

  • float---Float

  • double---Double

  • char---Character

  • boolean---Boolean

1.2、特点

  • 1.八个包装类都在同一个包下 java.lang包 不需要import导包直接使用

  • 2.八个包装类中有六个是与数字相关 都默认继承父类Number

  • 3.八个包装类都实现了Serializable, Comparable

  • 4.八个包装类都有带自己对应类型参数的构造方法 八个包装类中有七个(除了Character)还有构造方法重载 带String类型

  • 5.创建对象 对象调用方法 有六个与数字相关的类都继承Number ,xxxValue(); 将一个包装类类型转化为对应的基本类型(拆包)

    public static void main(String[] args){
//      Demo demo = new Demo();
//      Demo demo2 = demo;
//      Demo demo3 = demo;
//      System.out.println(demo2==demo3);//true
        Integer i1 = 1;//自动包装,int转Integer
        int i2 = i1;//自动拆包
        int i3 = i1.intValue();//主动拆包
        System.out.println(i1.intValue());
    }

1.3、小细节问题

		Integer i1 = 10;
		Integer i2 = 10;
		Integer i3 = new Integer(10);
		Integer i4 = new Integer(10);
		System.out.println(i1==i2);//  true--->如果数字范围超过127false
		System.out.println(i1==i3);//  false
		System.out.println(i3==i4);//  false
		System.out.println(i1.equals(i2));//true
		System.out.println(i1.equals(i3));//true
		System.out.println(i3.equals(i4));//true
  • 本来Object中的equals()是比较两个对象的地址的,和==一样的作用。

  • 但Integer类中对equals()进行了重写,只比较值,不比较地址

  • 注意:i1==i2 // true--->如果数字范围超过127,false

    • 因为根据Integer源码,Integer里面的内部类有一个static Integer[] cache数组,长度为256,里面存了-128~127的Integer对象,如果数字在这个范围,就直接从cache中拿,所以i1、i2指向同一个地址

    • 如果超过了127,则会自己new一个Integer对象在堆内存中,所以i1、i2不相等

2、与数学相关的类

2.1、Math类

1、特点

  • 所属的包java.lang

  • Math构造方法是私有的 我们不能直接调用创建对象

  • 由于Math中提供的属性及方法都是static 不需要创建对象

2、常用方法

  • abs()返回给定数字的绝对值 (参数 int long float double)

  • double = ceil()向上取整

  • double = floor()向下取整

  • double = rint()临近的整数 如果两边距离一样 则返回偶数

  • int = round() 四舍五入的整数

  • max(a,b) min(a,b) (参数int long float double)

  • pow(a,b) a的b次方 (参数double 返回值double)

  • sqrt(double a) 获取给定参数的平方根

  • double = random(); 随机产生一个 [0.0--1.0)

    • Math.random()计算小数的时候精确程度可能有些损失

    • 0-9之间的随机整数 int value = (int)(Math.random()10); 5.0---10.9之间的小数 (Math.random()6)+5 0.0---0.99999 * 6 (0.0---5.99994)+5---损失了一些

2.2、Random类

1、特点

  • 在java.util包中,需要import导入

  • 没有任何继承关系 默认继承Object类

  • 创建对象--Random r = new Random();

2、常用方法

  • r.nextInt(); 随机产生 int取值范围的整数 有正有负

  • r.nextInt(int bound); 随机产生一个 [0--bound) 整数 注意bound必须为正数 否则会出现如下的运行时异常 IllegalArgumentException

  • r.nextFloat() 随机产生一个 [0.0---1.0)

  • r.nextBoolean() 随机产生一个boolean值 true false

2.3、UUID类

1、特点

  • 所属的包 java.util 需要import导入

  • 没有任何继承关系 默认继承Object类

  • 构造方法有 没有无参数的 我们通常不会创建对象

2、使用

UUID uuid = UUID.randomUUID();
System.out.println(uuid.toString());//数据库表格主键 primary key
//产生一个32位的随机元素 每一个位置是一个16进制的数字

2.4、BigInteger类

1、特点

  • 1.所属的包java.math 需要import导入

  • 2.继承自Number

  • 3.如何创建对象 提供的构造方法全部都是带参数的

    • 通常利用带String参数的构造方法创建这个类的对象

      • BigInteger bi = new BigInteger("123");

  • 4.范围:和long一样, -2的63次方 ~ 2的63次方-1

2、常用方法

  • 做四则运算 :add() subtract() multiply() divide()

2.5、BigDecima类

1、特点

  • 1.所属的包 java.math包

  • 2.继承Number类

  • 3.通常也是可以通过 带String参数 构建对象

  • 4.超过了double取值范围的时候使用

2、常用方法

  • 做四则运算 :add() subtract() multiply() divide()

3、说明

  • 根据effective java书中所说,只要是float、double型的小数,都不是准确的值

  • 因为二进制不能表示0.1、0.2类似的小数,只能表示0.5这样的(二进制为0.1)。

2.6、DecimalFormat类

1、特点

  • 1.所属的包 java.text

  • 2.import导入才能使用

  • 3.通过带String参数的构造方法创建一个格式化对象 0 #,0表示必须存在,#表示可有可无

2、使用

  • 调用format方法将一个小数格式化成一个字符串

DecimalFormat df = new DecimalFormat("000.###");//注意:当0的个数大于实际的个数,会添0,但#后面的加了多余的0会报错
String vlaue = df.format(12.45);
System.out.println(vlaue);

2.7、Scanner和System类

3、与日期相关的类

3.1、Date类

1、特点

  • 通常使用的是java.util包

  • 通常使用无参数的构造方法 或者带long构造方法

  • 可以处理一个Date日期的格式

2、常用方法

  • before()

  • after()

  • setTime() getTime() --->long

  • compareTo()--->-1 1 0

3.2、DateFormat类

1、特点

  • 包java.text 需要导包使用

  • 此类是一个抽象类 不能创建对象 子类来使用

  • SimpleDateFormat类 是DateFormat的子类

2、使用

  • 调用带String参数的构造方法创建format对象

Date date1 = new Date();//无参构造就是获得当前时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String v = sdf.format(date1);

3.3、Calendar类

1、特点

  • 所属的包java.util 需要导包

  • 有构造方法 用protected修饰的 通常访问不到 通常会调用默认的getInstance();

2、常用方法

  • after() before()

  • setTime() getTime()---->Date

  • getTimeInMillis()----time

  • getTimeZone()---TimeZone

  • Calendar里面包含一个date属性 可以 *** 作date的某一个局部信息

  • set get calendar.set(Calendar.YEAR,2015); int year = calendar.get(Calendar.YEAR);

		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.YEAR, 2001);//可以单独修改年、月、日
		Date date = calendar.getTime();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String v = sdf.format(date);
		System.out.println(v);

3.4、TimeZone类

4、String类

4.1、特点

  • java.lang包

  • 没有任何继承关系 实现三个接口Serializable, CharSequence, Comparable

4.2、构建对象

  • String str = "abc"; //直接将字符串常量赋值给str (字符串常量池)

  • String str = new String();//无参数构造方法创建空的对象

  • String str = new String("abc");//带string参数的构造方法创建对象

  • String str = new String(byte[] )//将数组中的每一个元素转化成对应的char 组合成String

  • String str = new String(char[] )//将数组中的每一个char元素拼接成最终的String

4.3、String的不可变特性

  • String类中包含一个private final char[] value;

  • 体现在两个地方 长度及内容

    • 长度--->final修饰的数组 数组长度本身不变 final修饰数组的地址也不变

    • 内容--->private修饰的属性 不能在类的外部访问

4.4、常用方法

  • 1.boolean = equals(Object obj); 继承自Object类中的方法 重写啦 改变了规则 比较字符串中的字面值 == equals()区别 equalsIgnoreCase();

  • 2.int = hashCode(); 继承自Object类中的方法 重写啦 31*h+和

  • 3.int = compareTo(); 实现自Comparable接口 实现方法 结果按照字典排布(unicode编码)顺序 按照两个字符串的长度较小的那个(次数)来进行循环 若每次的字符不一致 则直接返回code之差 若比较之后都一致 则直接返回长度之差 compareToIgnoreCase();

  • 4.String = toString() 没有重写过的toString从Object类中继承过来的 类名@hashCode(16进制形式) String类重写啦 返回的是String对象的字面值

  • 5.char = charAt(int index); 返回给定index位置对应的字符 int = codePointAt(int index); 返回给定index位置对应字符的code码

  • 6.int = length(); 返回字符串的长度 (其实就是底层char[] value属性的长度) 注意: 区别数组length是属性 String的length()方法 集合size()方法

  • 7.String = concat(String str); 将给定的str拼接在当前String对象的后面 注意: 方法执行完毕需要接受返回值 String的不可变特性 concat方法与 +拼接的性能问题 开发中若遇到频繁的拼接字符串--->通常使用StringBuilder/StringBuffer

  • 8.boolean = contains(CharSequence s); 判断给定的s是否在字符串中存在

  • 9.startsWith(String prefix); endsWith(String suffix); 判断此字符串是否已xx开头/结尾

  • 10.byte[] = getBytes(); ---> getBytes(String charsetName); char[] = toCharArray(); 将当前的字符串转化成数组 "我爱你中国" char[] '我' '爱' '你' '中' '国'

    1. int index = indexOf(int/String str [,int fromIndex] ); 四个方法重载 找寻给定的元素在字符串中第一次出现的索引位置 若字符串不存在则返回-1 lastIndexOf(int/String str , [int fromIndex]); 找寻给定的元素在字符串中最后一次出现的索引位置 若不存在则返回-1

  • 12.boolean = isEmpty(); 判断当前字符串是否为空字符串 (length是否为0) 注意: 与null之间的区别

  • 13.replace(); replaceAll(); replaceFirst(); 换第一次出现的那个字串 将给定的字符串替换成另外的字符串

  • 14.String[] = split(String regex [,int limit限度界限]); 按照给定的表达式将原来的字符串拆分开的

  • 15.String = substring(int beginIndex [,int endIndex]); 将当前的字符串截取一部分 从beginIndex开始至endIndex结束 [beginIndex,endIndex) 若endIndex不写 则默认到字符串最后

  • 16.String = toUpperCase(); String = toLowerCase(); 将全部字符串转换成大写/小写

  • 17.String = trim(); 去掉字符串前后多余的空格

  • 18.boolean = matches(String regex) regular有规律的 expression表达式 正则表达式

4.5、StringBuilder类

1、特点

  • 所属的包 java.lang包

  • 继承AbstractStringBuilder 间接继承 Object

    • 实现接口Serializable,CharSequence,Appendable

  • StringBuffer/StringBuilder没有compareTo方法

  • StringBuffer/StringBuilder含有一个String没有的方法 append();拼接

  • 可变字符串 char[] value; 动态扩容

2、构造对象

//无参数构造方法  构建一个默认长度16个空间的对象  char[]
StringBuilder builder = new StringBuilder();
//利用给定的参数 构建一个自定义长度空间的对象 char[]
StringBuilder builder = new StringBuilder(20);
//利用带String参数的构造方法  默认数组长度字符串长度+16个
StringBuilder builder = new StringBuilder("abc");

3、常用方法

  • append(""):频繁的拼接字符串的时候使用此方法 提高性能

  • ensureCapacity(int minimumCapacity) 确保底层数组容量够用

  • capacity();//字符串底层char[]的容量

  • length();//字符串有效元素个数(长度)

  • setLength();//设置字符串的有效元素个数

  • char = charAt(int index);

  • int = codePointAt(int index);

  • String = substring(int start [,int end]);截取[start,end)的字符串

  • StringBuilder = delete(int start [,int end]);

    • StringBuilder类中独有的方法String类没有

    • 将start到end之间的字符串删掉 不用接受返回值就看到效果啦

  • StringBuilder = deleteCharAt(int index);

    • String类中没有的方法

    • 将给定index位置的某一个字符删除掉啦

  • int = indexOf(String str [,int fromIndex]);找寻给定的str在字符串中第一次出现的索引位置 带重载 则从某一个位置开始找

  • insert(int index,value);将给定的value插入在index位置之上

  • replace(int start,int end,String str);将start和end之间的部分替换成str,不包括end。

  • setCharAt(int index,char value);将index位置的字符改成给定的value

  • toString(); 将StringBuilder对象 构建成一个string对象 返回

  • trimToSize(); 将数组中无用的容量去掉 变成length长度的数组

5、正则表达式

1、简介

  • 一个带有一定规律的表达式

  • 匹配字符串格式的

2、作用

  • 1.字符串的格式校验 String类中提供的一个方法 boolean = str.matches("regex");

  • 2.字符串的拆分及替换 String类中提供的方法replace split

  • 3.字符串的查找 Pattern模式 Matcher匹配器

3、写法

  • [abc]:abc其中的一个

  • [^abc]:不能是abc其中的一个

  • [a-zA-Z]:表示必须是这两个范围内的

  • [a-z&&[.^bc]]:表示a-z其中的一个但不能是b和c

  • |:或者,实际上[]就是表示或者的意思

    • 如果我想表示与,则直接用字符串"abc",没必要用正则了。

  • . :表示任意一个字符

  • d:digit数字 [0-9]

  • D:非数字 [.^0-9](因为笔记格式问题,实际没有.)

  • s:space留白,空格、回车、换行

  • S:非留白

  • w:word单词 [0-9A-Za-z]数字或字母都可以

  • W:非单词 [.^0-9A-Za-z]

  • ?:0-1次

    • [0-9]?:表示数字只出现一次

  • *:0-n次

  • +:1-n次

  • {n}:固定n次

  • {n,}:至少出现n次

  • {m,n}:出现m-n次

6、JDK8新的日期类

6.1、出现背景

以前的日期类有很多问题:

6.2、新增包

6.3、相关类

1、LocalDate、LocalTime、LocalDateTime类

  • LocalDate类:代表IOS格式(yyyy-MM-dd)日期

  • LocalTime类:代表一个时间,时分秒

  • LocalDateTime类:代表日期和时间,最常用

常用方法

public class Test {
    public static void main(String[] args) {
        LocalTime localTime = LocalTime.now();
        System.out.println(localTime);//21:05:55.046
        System.out.println(localTime.getHour());//21
        System.out.println("-------------------------");
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime);//2021-10-18T20:53:17.560
        int i = localDateTime.getDayOfMonth();
        System.out.println(i);//18,当前月的第几天
        Month month = localDateTime.getMonth();//得到MAY.OCTOBER
        System.out.println(month.getValue());//10
    }
}

2、Instant类

2.1、简介

  • 时间线上的一个瞬时点。这可能被用来记录应用程序中的事件时间戳。

  • 精度可以达到纳秒级

2.2、常用方法

public class Test2 {
    public static void main(String[] args) {
        Instant instant = Instant.now();
        System.out.println(instant.toEpochMilli());//1634563446124
        System.out.println(System.currentTimeMillis());//1634563446124
    }
}

3、格式化与解析日期或时间

3.1、

  • java.time.format.DateTimeFormatter类提供了三种格式化方法

3.2、三种方法

1、方法一:预定义的标准格式

  • ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME

2、方法二:本地化相关的格式

  • 本地化相关的格式。如:static DateTimeFormater ofLocalizedDateTime(FormatStyle.LONG)

    • FormatStyle.FULL

    • FormatStyle.LONG

    • FormatStyle.MEDIUM

    • FormatStyle.SHORT

3、方法三:自定义格式(常用)

  • static DateTimeFormatter ofPattern(String pattern):返回一个指定字符串格式的DateTimeFormatter对象

    • 自定义格式:如ofPattern("yyyy-MM-dd hh:mm:ss")

格式化:

  • String format(TemporalAccessor t):格式化一个日期、时间,返回一个字符串

    • TimeporalAccessor是一个接口

解析:

  • parse(CharSequence text):将指定格式的字符串序列解析为一个日期、时间

    • CharSequence是一个描述字符串结构的接口

      • String、StringBuilder、StringBuffer类都实现了它

public class Test3 {
    public static void main(String[] args) {
        //方式一
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_LOCAL_DATE;//2021-10-18
        DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ISO_DATE_TIME;//2021-10-18T21:58:36
        	//格式化:日期-->字符串
        String format = dateTimeFormatter.format(LocalDateTime.now());
        String format2 = dateTimeFormatter2.format(LocalDateTime.now());
        System.out.println(format);
        System.out.println(format2);
        	//解析:字符串-->日期
        TemporalAccessor parse = dateTimeFormatter2.parse("2021-10-18T21:58:36");
        System.out.println(parse);//{},ISO resolved to 2021-10-18T21:58:36
        System.out.println("--------------------");
        //方式二
        DateTimeFormatter dateTimeFormatter3 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
        DateTimeFormatter dateTimeFormatter4 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
        	//格式化
        String format3 = dateTimeFormatter3.format(LocalDateTime.now());
        String format4 = dateTimeFormatter4.format(LocalDateTime.now());
        System.out.println(format3);//2021年10月18日 下午10时10分14秒
        System.out.println(format4);//2021-10-18 22:10:54
        	//解析
        TemporalAccessor parse3 = dateTimeFormatter3.parse("2021年10月18日 下午10时10分14秒");
        System.out.println(parse3);//{},ISO resolved to 2021-10-18T22:10:14
        System.out.println("--------------------");
        //方式三
        DateTimeFormatter dateTimeFormatter5 = DateTimeFormatter.ofPattern("yyyy-MM-hh HH:mm:ss");
        	//格式化
        String format5 = dateTimeFormatter5.format(LocalDateTime.now());
        System.out.println(format5);//2021-10-10 22:14:28
        	//解析
        TemporalAccessor parse5 = dateTimeFormatter5.parse("2021-10-10 22:14:28");
        System.out.println(parse5);//{MonthOfYear=10, Year=2021},ISO resolved to 22:14:28
    }
}

4、其他类

五、集合

1、List
  • 有序可重复

    • 序 : 顺序 添加进去的元素 取得元素的顺序一致 注意指的不是集合自己的顺序

    • 重复:两个对象元素一致

1.1、ArrayList

1、特点

  • 所属的包 java.util

  • 底层就是一个数组

  • 无参数构造方法 带默认空间的构造方法 带collection参数的构造方法

  • 默认扩容1.5倍,数组空间用完了才扩容

  • 有泛型:ArrayList arrayList = new ArrayList();

    • 存的类型就只能是T类型,不然所有类型都能存

2、常用方法

  • 存 add

  • 取 get

  • 删 remove

  • 改 set

  • 个数 size

  • add(E e) add(int index,E e) addAll(Collection c); add(int index,Collection c)

  • clear();将集合内的全部元素清除

  • boolean = contains(Object);找寻某一个给定的元素是否在集合中拥有

  • ensureCapacity(int minCapacity);

  • E = get(int index);

  • int = indexOf(Object obj); lastIndexOf();

  • boolean = isEmpty();

  • Iterator = list.iterator();//迭代器

  • remove(int index) remove(Object obj)

  • removeAll()差集

  • retainAll();交集

  • E = set(int index,E value)

  • int size();

  • List = subList(int begin,int end);

  • toArray(); 集合变成数组

    • toArray(T[] );

  • trimToSize();// 变成有效元素个数那么长

1.2、Vector

1、特点

  • java.util包

  • 是ArrayList集合的早期版本

    • Vector底层也是利用(动态)数组的形式存储

    • Vector是线程同步的(synchronized) 安全性高 效率低

  • 扩容方式与ArrayList不同,默认是扩容2倍 可以通过构造方法创建对象时修改这一机制

1.3、Stack

1、特点

  • 1.java.util包

  • 2.构造方法只有一个无参数

  • 3.除了继承自Vactor类的方法外还有特殊的方法

    • push(E e)将某一个元素压入栈顶(add())

    • E = pop()将某一个元素从栈顶取出并删掉(E = remove())

    • E = peek()查看栈顶的一个元素 不删除(get())

    • boolean = empty()判断栈内元素是否为空(isEmpty())

    • int = search()查找给定的元素在占中的位置(indexOf())

1.4、linkedList

1、特点

  • 1.java.util包

  • 2.底层使用双向链表的数据结构形式来存储,适合于插入或删除 不适合遍历轮询

  • 3.构建对象,无参数构造方法 带参数的构造方法(collection)

2、常用方法

  • 增删改查 add() remove() set() get() size() offer poll peek 手册中提供的其他常用方法 addAll addFist addLast() clear() contains() element() getFirst() getLast() indexOf() lastIndex()

2、Queue接口
  • 有序可重复

2.1、特点

  • java.util

  • 通常子类linkedList ArrayDeque

  • 通常无参数构造方法创建

2.2、常用方法

  • add() element()---->get() remove() boolean = offer(E e);//相当于add 不会抛出异常 E = peek();//相当于 element方法 E = poll();剪短// 相当于remove()

3、Set
  • 无序无重复

    • 无序:我们使用集合存放元素的顺序 集合内取出来的顺序不一致

    • 集合本身是有自己的算法排布顺序 hash算法

3.1、HashSet类

1、特点

  • 1.java.util

  • 2.如何创建对象 无参数 有参数

  • 3.如果添加了重复元素,则拒绝存入,不会覆盖

2、常用方法

  • 增删改查

  • boolean = add(value) addAll(collection c)

  • retainAll removeAll

  • boolean = remove(Object) 没有修改方法

  • iterator() 获取一个迭代器对象--用于遍历

Iterator iterator = treeSet.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
  • size()

3、无重复的原则

  • 用重写的equals()方法和hashCode()方法

3.2、TreeSet类

1、特点

  • java.util

  • 无参数构造方法 带Collection构造方法

2、常用方法

  • add(E e) iterator() remove(E e) 没有修改 size()

4、Map
  • key无序无重复

    • key无重复当然指的是 元素不能一致

    • 如果是对象,则地址不能一致

  • value无序可重复

4.1、HashMap类

1、特点

  • 包 java.util

  • 创建对象:HashMap hashMap = new HashMap<>();

2、常用方法

  • 增put(key,value) 存放一组映射关系 key-value

    • 1.key存储的顺序与取得顺序不同

    • 2.不同的key可以存储相同的value

    • 3.key若有相同的 则将 原有的value覆盖而不是拒绝存入(跟set刚好相反)

  • 删E = remove(key);

  • 改put(key,value1) put(key,value2) replace(key,newValue)

  • 查E = get(key)

  • size();

  • clear containsKey(key) containsValue(value)

  • getOrDefault(key,defaultValue);如果key存在就返回对应的value 若没有找到则返回默认值

  • isEmpty() putAll(map) putIfAbsent(key,value);//如果key不存在才向集合内添加 如果key存在就不添加啦

3、遍历

  • 遍历map集合? key不一样 获取到所有的key 遍历key 通过key获取value Set = keySet()获取全部的key Set = entrySet();

4、使用情景

4.2、TreeMap类

六、异常 1、错误error
  • Error错误:通常是一些物理性的,JVM虚拟机本身出现的问题,程序指令是处理不了的

2、Exception异常
  • 通常是一种人为规定的不正常的现象,通常是给定的程序指令产生了一些不符合规范的事情

2.1、运行时异常

  • 不报错,运行时可能发生的异常,一般不会发生异常就使用运行时异常处理

1、特点

  • Error和RuntimeException都算作运行时异常

  • javac编译的时候,不会提示和发现的

  • 在程序编写时不要求必须做处理,如果我们愿意可以添加处理手段(try throws)

2、常见运行时异常

2.2、编译时异常

1、特点

  • 除了Error和RuntimeException以外其他的异常

  • javac编译的时候 强制要求我们必须为这样的异常做处理(try或throws)

    • 因为这样的异常在程序运行过程中极有可能产生问题的

  • 异常产生后后续的所有执行就停止啦

InterruptException
			try{
				Thread.sleep(5000);
			}catch(Exception e){
	
			}
3、处理异常
  • try{}catch(){}[ finally{} ]

1、特点

  • 1.try不能单独的出现

  • 2.后面必须添加catch或finally

  • 3.catch有一组括号 (NullPointerException) 目的是为了捕获某一种异常

  • 4.catch可以有很多个存在

    • 捕获的异常之间没有任何的继承关系

    • 捕获的异常需要从小到大进行捕获

  • 5.finally不是必须存在的

    • 若存在finally结构 则必须执行

    • 引申一个小问题: final finally finalize区别

  • 6.处理异常放在方法内部 可能还会有小问题

    • 如果在方法内部含有返回值,不管返回值return关键字在哪里 finally一定会执行完毕,

4、Throws抛出
  • 1.异常只能在方法上抛出 属性是不能处理异常的

  • 2.方法 构造

  • 3.方法可以抛出不止一个异常 通过,隔开

  • 4.抛出的异常与多个catch类似 要么没关系 要么先抛出小异常

5、自定义异常

  • 注意子类重写方法抛出的异常不能大于父类被重写方法的异常

    • 即父类方法有异常IOException,子类重写方法可以没有异常,但不能抛出Exception异常

6、开发中如何选择

6.1、自定义如何选择RunException或者Exception

  • 当父类方法抛出的是RunException时,子类重写就必须用RunException

  • 不报错,运行时可能发生的异常,一般不会发生异常就使用运行时异常处理

6.2、处理异常时,如何选择try catch[finally]或者throws

  • 当父类没有抛出异常时,子类重写的方法想处理异常就必须用try catch[finally]

  • 当一个方法A中调用了多个方法BCD,而且BCD都有异常,而且BCD执行有递进关系,就是方法的返回值作为另一个方法的参数,这时,BCD方法推荐使用throws抛出异常。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5576547.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存