JavaSe一个月一些笔记和感想

部分常识

  1. dos指令(win和Linux上删除指令不太一样
  2. java环境变量设置,尽量不要设置出中文名称变量,后续会影响路径读取
  3. public只能修饰一个类,且该类的名称和文件名称一致,同一文件中可以有多个类
    1. 类、方法、常量的基本命名规范和规则
      1. 标识符:java 对类名 方法名 变量名 包名 等命名时采用的字符序列。
        1. 在java中凡是需要自己命名的位置都是标识符
          1. 标识符命名规则:
            1. 由字母数字下划线美元符组成,且数字不能开头
            2. 不能用保留字和关键字
            3. 严格区分大小写
          2. 命名规范
            1. 看到名字要知道这玩意大概啥意思
            2. 类名各个单词首字母大写
            3. 方法(函数)名第二个单词首字母大写(其之后的所有单词首字母大写)
            4. 包名小写
            5. 常量全部大写
          3. 命名规则:
            1. 字母数字下划线 美元符 组成
            2. 数字不能开头
            3. 不能是java中的关键字或者保留字
            4. 严格区分大小写
          4. 命名规范:
            1. 见名之意
            2. 类 每一个单词的首字母大写
            3. 方法 变量 等 第一个单词的首字母小写 从第二个单词开始 首字母大写
            4. 包 所有字母小写
            5. 常量 所有的字母大写 多个单词组成 使用下划线连接
            6. 局部变量需要初始化,即放在方法中的变量要初始化
            7. 放在方法外的因为其是类变量所以可以不做初始化
  4. ASCLL码:0:48,A:65,a:97
  5. byte,short,char三者任意之间运算,结果都会转换为int类型
  6. +=,-=,/=,%=之类的赋值运算符不会改变原有的数据类型
  7. charAt方法只能接收空格前的数据
  8. nextLine只能跟随nextLine的输入,如果上一输入不是nextLine则会中断
  9. 随机数公式
    1. Math.random()*(n-m+1)+m
    2. 取值范围[m,n]

循环控制部分


  • switch(数据){}

    • 数据中可以放的数据类型char,int,String,short,byte,枚举
  • do{循环体}while();

    • 一般先执行一次循环体的内容,再进行条件判断
  • 随机数公式

    • Math.random()*(n-m+1)+m
      取值范围[m,n]
  • 循环选择

    • for适用条件 循环次数固定
    • while 循环次数不固定
    • do while 初始化条件不满足循环条件,但仍执行一次循环
  • 嵌套循环内break

    • 如果没有标签,则结束当前break所在层循环,如果有标签,结束标签所在循环

      • 标签

        l: for(i=0;i<x;i++){ 
            for(j=0;j<x;j++){
            if(a==b)
            brake l;}} 
        
  • 嵌套循环内continue

面向对象

包(package)命名

  • 名称小写
  • 模块名+网址(不用www om.baidu)

静态成员变量与非静态成员变量

  1. 相同
    • 都有默认值
    • 都是类变量
  2. 不同
    • 内存位置不同
    • 静态存在方法区
    • 非静态存在堆中
  3. 调用方式不同
    • 静态成员变量可以通过,
      • 类名.属性名,
      • 对象名.属性名调用(不推荐)
    • 非静态成员变量只能通过
      • 对象名.属性名调用
  4. 在内存中的份数不同
    • 静态成员只会开辟一块,所有对象共用这一块
    • 非静态new一次创建一次
  5. 创建时间不同
    • 静态成员变量 在类加载时开辟,随着类的加载而加载
    • 非静态成员变量 在创建对象是创建
  6. 销毁时间
    • 静态成员变量 随着类的卸载而销毁
    • 非静态变量 当没有应用指向时,会被垃圾回收器回收销毁

方法

  1. 形参:

    • 存在:方法声明处
      • 规定调用出传递的实参类型、个数、顺序
      • 在定义方法时方法名后面括号中声明的变量称为形式参数(简称形参)即形参出现在方法定义时。
        • 形参是基本数据类型,那么实参给形参的是数据值的副本,形参的修改不影响实参;
        • 形参是引用数据类型,那么实参给形参的是地址值的副本,形参对象修改属性相当于实参对象修改属性
  2. 实参

    • 存在:方法调用处
    • 可以是变量也可以是常量,与形参类型匹配即可
    • 调用方法时方法名后面括号中的使用的值/变量/表达式称为实际参数(简称实参)即实参出现在方法调用时。
    • 静态方法
      • 声明时,有static关键字
      • 调用时,类似静态变量
      • 类名.方法名();
  3. 资源引用上,能直接调用静态资源

  4. 如果想调用非静态资源,可以new一个对象进行间接调用

  5. 在本类中可以直接调用,在其他类中需要用该方法所在类的类名.方法名
    生存周期:和静态变量一样

非静态方法
声明时,没有static关键字
调用时,类似实例变量
对象名.方法名();
注意点:在同一个类中运行时,可以省略类名/对象名,直接调用

​ 资源引用上,可以直接调用所有的资源
​ 生存周期:和非静态变量一样

成员变量/局部变量
声明位置:
类中/该方法中

​ 作用域:
​ 类/该方法中

​ 默认值:
​ 有/无

​ 内存位置:
​ 堆中/栈中

​ 生命周期:
​ 类开辟->没有指向,垃圾回收/方法调用->方法结束

重载
定义:同一个类中,允许存在多个同名方法,只要其参数个数或参数类型不同
两同一不同
同一个类,同一个方法名
不同的参数类型或参数个数

判断是否重载
与方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系

可变参数
底层是通过数组构建的
可接受的参数个数为【0,n】
必须位于参数列表最后
一个方法只能有一个可变参数

对象数组
类似二维数组,但其内部存储的是一个对象(对象内部又有其他的属性)

递归
直接递归
间接递归
注意点
递归需要有出口
不断的向出口靠近
当递归次数过多时,会出现StackOverflowError错误

封装
访问控制权限
封装的作用
防止出现垃圾数据,可以对属性进行封装
private 数据类型 变量名,同时也要提供方法去改变或者获取该变量
利用this区别成员变量和局部变量

构造器
构建方法
[修饰符] 类名(形参列表){方法体}

类的新建都会有一个默认构造器(前提是改类中没有构造器)
当写入一个带参构造器,默认构造器自动丢弃(可重新手动写入)
支持重载
构造器通过new关键字调用
注意点
1.当类中没有构造器时 就会有一个默认的 隐藏的 无参的构造器
一旦写了有参构造器 那么默认的 隐藏的 无参的构造器 自动消失

​ 2.构造器通过 new 关键字调用
​ 3.构造器的作用 快速给成员变量赋值
​ 4.区分局部变量 与成员变量使用this
​ 5.构造器支持重载的

继承
注意点:
继承的子类在使用资源时,一般现在本类中寻找,如果没有则到父类(上一级)中寻找,不断往上,直到object
一个类没有显示的继承一个类,那么这个类默认继承object类
Java中的继承是单继承,一个类只能直接继承另一个类。但可以多重继承(深度,一脉单传)
关于私有属性,其子类不能直接调用和使用(但可以通过getXxxxx/setXxxxx整活)

重写
子类重新构建父类的方法
要求:权限修饰符 返回值 方法名(参数列表){方法体}
其中权限修饰符必须比父类更广,即不能比父类更加严格
关于返回值类型
如果是基本数据类型 那么必须与父类保持一致
如果是引用数据类型 那么可以和父类保持一致,也可以是父类的子类

​ 方法名必须与父类保持一致
​ 形参列表必须与父类保持一致
​ 注意:静态方法没有重写的概念,因为其属于类的,但其可以被继承

this的使用
this代指当前对象,谁调用就是谁
this可以调用属性、方法
this可以调用本类中的构造器,但必须位于首行,一般是多参数的调用少参数的
注意:静态方法不能使用this,因为当你调用静态方法时,类还没有实例化(因为可以直接类名. 方法名调用)

super
从父类继承的资源(属性、方法、构造器)
注意:调用构造器时,this调用和super调用只能出现一个,同时静态方法也不能调用super方法

成员初始化赋值
默认赋值
显示赋值
和代码块看谁在前,谁前谁先(静态例外)

代码块赋值
普通代码块赋值
使用形式 { 赋值内容 } 等价于普通方法
位置:类中方法外
作用,给普通成员变量赋值
注意:
有作用域限制
执行先于构造器
建立一次对象执行一次

​ 静态代码块赋值
​ 形式 ststic{ } 等价于静态方法
​ 位置:类中方法外
​ 作用,给静态成员变量赋值
​ 注意:
​ 有作用域限制
​ 执行先于普通代码块执行
​ 无论建立多少对象,该代码块只会执行一次

构造器赋值
对象名. 属性/方法赋值
上述赋值顺序自上而下
初始化
类的初始化
给类中的静态成员变量显示赋值语句,静态代码块内容合并到
只会执行一次

​ 实例初始化(神奇的new特例)
​ 默认值
​ 普通成员变量显示赋值
​ 普通代码块
​ 构造器
​ 有父子类继承关系,先有默认值,再进行父类的实例初始化,然后进行子类的实例初始化(先静态后普通)。
​ 上述会合并到<init中>

多态
前提
有继承
有方法重写

向上转型
前提
父类的引用指向子类的实例(对象)
B继承A
A a = new B ( )

​ 方法引用问题
​ 编译看左边,运行看右边 相较于“=”
​ 注意:不能使用子类自身新增资源(因此引入向下转型)

​ 应用
​ 对象数组
​ 建立父类的对象数组,其数组内可以是父类的子类对象

​ 返回值
​ 方法返回的可以是父类的子类对象

​ 形参
​ 方法形参其传入的参数可以是父类的子类对象

向下转型
类似基本数据类型的强制转换int a=(char)a
instanceof关键字
判断当前类型属于左边还是右边
有点像if判断
其是按照继承关系进行查找

​ 向下转型后可以调用子类自身的方法和属性

非虚方法
不可以重写的方法
java中主要有三种
由invokestatic指令调用的static方法,这种方法在编译时确定在运行时不会改变。
由invokespecial指令调用的方法,这些方法包括私有方法,实例构造方法,这些方法也是在编译时已经确定,在运行时不会再改变的方法
由final关键字修饰的方法。虽然final方法是由invokevirtual指令进行调用的,但是final修饰的方法不能够进行在子类中进行覆盖,所有final修饰的方法是不能够在运行期进行动态改变的。在java语言规范中明确规定final方法就是非虚方法。

虚方法
可以重写的方法
静态分派:先看这个对象的编译时类型,在这个对象的编译时类型中找到最匹配的方法, 最匹配的是指,实参的编译时类型与形参的类型最匹配
动态绑定:再看这个对象的运行时类型,如果这个对象的运行时类重写了刚刚找到的那个最匹配的方法,那么执行重写的,否则仍然执行刚才编译时类型中的那个方法

native
被native 修饰的方法
本地方法
public native int hashCode();

本地方法 没有方法体 但是可以直接使用
本地方法调用时 会在本地方法栈内开辟空间

final
final修饰的类 不能被继承 不能有子类 声明方式 final class 类名
final 修饰的方法 不能被重写 声明方式 public final void eat(){}
final的注意点
修饰的变量 变为 常量
修饰的对象 地址值不能改变
修饰的成员变量 可以显示赋值 也可以通过构造器赋值
但需要注意的是:这个只能赋值一次,类似初始化,之后就不能修改了

object
其为所有类的根父类
任意对象 都可以使用Object类中的方法
数组也是对象 也可以使用
除了Object 类之外 所有的类 都可以写出向上转型的关系

equals
比较两个对象是否相等
重写前 调用的是Object类中的equals 比较的是地址值 (this == obj);
重写后 比较的是属性值

​ ==
​ 基本数据类型 比较的是数值
​ 引用数据类型 比较的是地址值

getClass
获取运行时类型

hashcode
获取当前对象的哈希码
哈希码 对象不同肯定不同
哈西码相同 对象也不一定相同

toString
如果单独输出对象的名字 会默认调用该对象的toString()
重写toString() 要快速展示 属性信息

抽象类
抽象:既不具体,也无法具体
抽象类声明方法:abstract class 类名{}
抽象方法:规定子类行为
权限修饰符 abstract 返回值类型 方法名(形参);

抽象类中可以存在普通属性/方法
抽象类中可以没有抽象方法
抽象方法必须存在抽象类中
一个类继承了抽象类 那么此类要么实现所有抽象方法,要么此类变成抽象类
抽象方法不能被静态(static)、私有(private)、final修饰

接口
用来定义规范 has a 的关系
接口声明:interface 接口名{ }
使用:class 类名 implements 接口名{ }
接口成员
接口属性是全局静态常量,其默认被public static final修饰
接口的抽象方法,默认被public、abstract修饰
接口内可以有静态的方法,默认被public修饰
接口内有默认方法 哪一个实现类需要重写 直接重写即可 不会对其他类造成影响,其默认被 public 修饰
声明方式【public 可有可无】 default 返回类型 方法名
那个实现类需要则重写,不会对其他类造成影响

注意:
一个类实现了接口,那么此类需要实现接口内所有的抽象方法,否则此类变成抽象类
可以存在普通方法

​ 接口不能直接创建对象
​ 如果一个类实现了接口 可以把此类看成是该接口的孩子

Java中接口可以多实现
如果实现多个接口,有同名的默认方法,那么必须对重名方法重写
如果继承一个类,又想要实现接口,必须先继承再实现接口(如果有同名的方法,优先调用继承的)
接口可以实现多继承

几个比较经典的接口
java.lang.Cloneable标记接口
@Override 校验当前方法是否为重写的方法
@Deprecated 标记过时
过时的资源 不推荐使用 已经有了更好的方式替代

​ @SuppressWarnings 抑制警告
​ @SuppressWarnings("all") 抑制所有的警告

​ java.lang.Comparable:内部比较器
​ 让需要比较对象的类,实现Comparable接口
​ 重写compareTo方法
​ 在方法内完成比较规则的制定
​ >0 前一个对象>后一个对象
0 前一个对象后一个对象
​ <0 前一个对象<后一个对象

​ 使用数组工具类 比较自定义类型数据 必须 让此类型 实现 Comparable 接口 制定比较规则

​ java.util.Comparator:外部比较器(定制比较器)
​ 可以在比较对象的外部完成比较规则的制定
​ 先创建一个类实现comparator接口
​ 重写compare(object a,object b)
​ 在需要比较的对象位置,创建比较规则类的对象
​ 规则:
​ >0 前一个对象 > 后一个对象
​ ==0 前一个对象 = 后一个对象
​ <0 前一个对象 <后一个对象

​ 该对象调用compare()

实现对象克隆,做两件事
1.实现Cloneable 接口
2.重写clone()

内部类
成员内部类(不常用)
常见于源码
声明方式
外部类名{ class 内部类名{ } }

​ 外部类只能被public,default修饰。成员内部类可以被所有访问权限修饰
​ 成员内部类
​ 内部不能有静态的资源,但可以有静态的常量
​ 可以使用外部类所有资源
​ 可以打破单继承的限制,即内部类还可以继承一个类

​ 在外部创建一个内部类对象
​ 外部类名.内部类名 对象名=new 外部类名(). new 内部类名()

​ 内部类会生成独立的字节码文件 命名方式 外部类名内部类名.class Outer$Inner.class
​ 每一个类中都有一个this 使用外部类中的this 外部类名.this.资源名

静态成员内部类(不常用)
常见于源码
静态内部类可有静态资源
可直接使用外部类静态资源,间接使用外部类非静态资源(新建一个外部类对象调用)
外部类引用内部类资源
静态资源通过 内部类名 . 资源名
非静态资源通过 内部类对象名 . 资源名

​ 在外部直接使用内部类资源
​ 静态资源 外部类名.内部类名.资源名
​ 非静态资源 先创建内部类对象
​ 外部类名.内部类名 对象名 = new 外部类名.内部类名();

​ 会生成独立的字节码文件 命名格式 Outer$Inner.class

局部内部类(一般)
写在方法内的内部类局部内部类
局部内部类 只有一个访问权限 default
不能有静态资源 可以静态的常量
局部内部类地位比较低 使用什么资源 是由所在方法决定
会生成独立的字节码文件 命名方式
外部类名$序号内部类名.class 序号从1开始
Outer$1A.class
Outer$2A.class

​ 使用局部内部类资源 需要创建局部内部类对象
​ 如果局部内部类使用了 该类所在方法的局部变量 那么该变量会被final修饰

匿名内部类(常用)
没有名字的内部类 其目的是简化代码
单独创建完匿名内部类两个作用
1.完成了该类匿名子类创建
2.完成了该类匿名子类对象创建

​ 创建匿名内部类的方式:
​ new 类(){};
​ new 接口(){};

​ 注意点
​ 匿名内部类又独立的字节码文件 命名方式
​ 外部类名$序号.class 序号从1开始
​ Test$1.class

​ 匿名内部类是特殊的局部内部类

单元测试
@Test,有网络的情况下
单元测试必须是公共的类
单元测试必须是公共的方法
方法名无要求
不要混杂其他无关内容

@before,执行单元测试方法前,会执行的内容
@after,执行单元测试方法后,会执行的内容
无网络
在当前模块下新建lib文件夹
把jar包导入该文件夹中(需要些许操作使其可用)
使用资源

数组


一维数组
初始化:
动态:type[] var=new type[length];var[0]=x;var[1]=y;····
通俗讲就是声明与赋值分开进行,相对常用点。即只知道数组长度,不知道具体元素内容

​ 静态:
​ 方式一type var[]=new var[]{x,y,z····}
​ 方式二type[] var={x,y,z····}
​ 注意点:
​ 通俗讲就是声明之后同时进行赋值,即写完后就知道数组内元素是那些
​ type[] var={x,y,z····}声明和赋值必须写到一起
​ type var[]=new var[]{x,y,z····}声明和赋值可以分开
​ 特别注意一种错误写法:type var[]=new var[length]{x,y,z····}

​ 对上述中部分运算符号进行说明
​ new运算符,为数组申请和分配内存空间
​ length属性(类似一个内置函数),计算数组长度

​ 对上述两种初始化方式说明:
​ 说明:type是声明的数组类型如:int、double、String····
​ 注意:纯粹声明时不能指定数组长度,同时如果初始化后其长度是不可变化的,不建议这样分开声明,太绕了。
​ (不能先声明后赋值,只能声明的同时赋值)

遍历:
循环遍历下标,for循环
循环遍历加强版,for(数组元素类型 变量名:数组名){变量名:数组内的元素}

Arrays工具类
Arrays.fill()批量填充

一维数组扩容
本质是再新建一个数组,然后把新数组的内存地址给旧数组,达到扩容目的(一般只会扩大1.5或2倍)

数组拷贝
System.arraycopy(src, srcPos,dest ,destpost ,length );

Array工具类
批量添加 fill
copyOf 复制
sort() 排序
binarySearch() 二分查找
equals() 比较
toString 输出

异常


异常的体系结构
Throwable
Error:程序员不需要处理的异常
Exception : 程序员处理的异常(这个是编译时异常)
运行时异常:代码真正跑起来 才会出现的异常
数组下标越界
空指针
算数异常
类型转换
输入不匹配

​ 编译时异常/检查异常/受检异常: 写完代码就报错
​ 编译时异常: 写完代码就报错 必须处理

两个比较好用的方法
getMessage();获取发生异常的原因
printStackTrace();发生异常的原因

异常的抛出
try { 可能发生异常的代码 }catch(异常类型 变量名){ 异常解决方案 }
注意
1.try中发生了异常 那么 异常下面的代码不会执行 直接进到 catch内
2.try{} 是有作用域限制 想要在其他位置使用需要进行作用域提升
3.只有发生了对应的异常类型 才可以进行捕获
4.想要捕获多个异常
4.1 使用 | 进行连接 catch(异常类型1 | 异常类型2 | .... 变量名)
4.2多重catch
4.3使用父类
如果存在多重catch 一定按照 从小到大的顺序写

​ try{ 可能发生异常的代码 }catch(异常类型 变量名){ 异常解决方案 }finally{ 无论如何都要执行的代码 }
​ 强制退出 jvm System.exit(0);一般在这的用处就是强制退出提前finally代码,比如加在catch中,那么就不会执行finally了

在方法内 使用 throw 异常对象;
在会异常处使用↓,手动抛出异常
throw new 产生的异常名称()
注意
throw在方法内
抛出异常对象
后面只能有一个异常对象

throws 给方法调用者提示
throws 在方法的声明处
给方法调用者提示 会发生哪些异常
可以有多个异常类型

注意
如果抛出 编译时异常 必须使用throws声明
如果抛出 运行时异常 既可以声明也可以不声明

继承关系的异常抛出
父类抛出的是运行时异常 子类抛出异常没有约束
父类抛出的是编译时异常 子类不能抛出比父类更大的异常

自定义异常
1.新建一个类型 继承一个异常类型
编译时异常 继承一个编译时异常类
运行时异常 继承一个运行时异常类

2.创建两个构造器
一个无参
一个String 参数
注:如果抛出的是 编译时异常类型 哪里调用 哪里处理

单元测试
单元测试如何使用
注意:
1.单元测试方法 必须是 公共的类
2.单元测试方法必须是 公共的方法
3.方法名无要求
4.单元测试类 不要混杂其他内容
@Before 运行单元测试方法前 会执行的内容
@After 运行单元测试方法后 会执行的内容

异常处理注意事项
编译期异常必须处理,要么捕获处理,要么声明在方法上,让调用者处理。
运行时异常被抛出可以不处理。即不捕获也不声明抛出。
try语句范围要尽量小的包围在可能出现异常的一行或几行代码上,不要把大量无异常的代码一起包起来,虽然这样很省事。
catch语句捕获的异常类型要尽量小,尽量精准,好针对性的做处理。
如果finally有return语句,永远返回finally中的结果,但要避免该情况.
如果父类方法抛出了多个异常,子类重写父类方法时不能抛出更大异常,可以抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。

遇到的一些坑,细节问题


float a=3.14f;此处需要加上f/F
long a=234l;此处需要加上l/L
输入不匹配异常,在输入中,接收int但输入double等
输入
next()方法:
遇到空格等空白符,就认为输入结束

nextLine()方法:
遇到回车换行,就认为输入结束

witch不能作用long,JDK1.7可以String
break:只能用在switch和循环内
continue:只能在循环内
数组长度为Arr.length,其最后一个元素的索引为Arr.length-1
字符串比较中,==比较的是字符串的内存地址,字符串相等用q1.equals(q2)
数组定义
一维数组
int[] len=new int[length]
此处动态声明有长度

​ type var[]=new var[]{x,y,z····}
​ 此处静态声明没有长度

二维数组
int[][] arr=new int[x][];
arr[x-1] = new int[y];
两行代码一起使用,注意第二行最开始没有再声明数据类型

对象实例化要在main中
private是不同包下的子类可见,注意是在类中可见,而不是对象中可见
静态方法没有重写(static)
空指针不能调用对象方法,(返回是一个空null,不能调用一些方法,会报空指针异常)
导model时维持原文件名一致
新建一个类对象时,会先加载父类的资源,然后才会加载子类的资源(static另外考虑,会先加载static的,然后按照这个考虑)
静态资源无法通过this调用
代码块声明的变量有作用域
枚举中的属性,必须位于枚举元素的下边,枚举类的构造器默认私有
泛型不能放基本数据类型
单元测试,@before 是个很好玩的东西
Comparable内部比较器
泛型只能放包装类型
Java 中的两种排序方式:
Comparable 自然排序。(实体类实现)
Comparator 是定制排序。(无法修改实体类时,直接在调用方创建)
同时存在时采用 Comparator(定制排序)的规则进行比较。
对于一些普通的数据类型(比如 String, Integer, Double…),它们默认实现了Comparable 接口,实现了 compareTo 方法,我们可以直接使用。
而对于一些自定义类,它们可能在不同情况下需要实现不同的比较策略,我们可以新创建 Comparator 接口,然后使用特定的 Comparator 实现进行比较。

comparable自然顺序
comparator杂乱的顺序也可以
run和start不能一起调用
子类异常不能抛出,原因有子类重写父类方法,不能抛出比父类更大的异常(父类没抛出异常,子类也不能)

感想


本憨憨以前学习的是Python,所以对于Java中很多问题都感觉很熟悉,但有时候会找不到解决方法,很多时候多是依靠百度,做题时,或多或少会受到之前Python语法上的苦恼(语法要求格式不同,语法也有一定差异),虽然Java学起来相对有点吃力(以前Python学的也不是很好,做的一些爬虫和数据分析挖掘相关的,但人很菜),但总体来讲还是有较大收获,还在持续学习和梳理后面多线程那些的笔记,不确定还会不会想起来放出来。

尾巴


由于是我临时想发布,之前用的幕布写的,复制出来不是md格式,所以一些笔记还没有做好排版,后续如果有时间会做下排版问题。

posted @ 2021-08-28 21:18  KaneQi  阅读(39)  评论(0编辑  收藏  举报