• 【后端】Java学习笔记(二周目-1)


    环境

    安装JDK8并配置环境变量

    jvm+核心类库=jre
    jre+开发工具=jdk

    Java基础运行流程,代码从上到下,从左往右,只运行一次

    桌面—>新建文件夹—>新建记事本—>打开编写代码

    public class Hello{
     	public static void main(String[] args){
    		System.out.println("Hello luckyNwa ");
    	}
    }
    

    —>修改记事本名称为 Hello.java ---->路径栏输入cmd回车出现终端---->

    javac Hello.java  
    

    ---->生成class文件—>运行

    java Hello
    

    过程:源文件A.java—>javac编译—>A.class—>java运行到JVM中

    再打印中加入中文发现乱码,解决

    文件改成ANSI格式另存覆盖原来的utf-8 或者在javac那指令改成如下

    javac -encoding UTF-8 Hello.java 
    

    IDEA的快捷键

    ctrl+/ 单行注释

    /**回车 文档注释

    /* */ 多行注释

    shift+ctrl+enter 光标到下一行,也可以补齐;

    mian 生成入口函数

    alt +enter 用于前面的变量定义 比如 new Scanner(System.in);

    ctrl+n 查类的说明文档 比如Math类

    fori 回车直接打出循环 数组a.for回车 foreach快捷键

    shift+tab 向前退一格

    ctrl+alt+t 可以添for while try catch 等

    命名规范

    标识符(变量)规则:由字母,数字,下划线和$组成,不能以数字开头 ,不能用关键字

    业内规定:

    类:首字母大写,驼峰命名法

    包:小写字母组成,域名倒置

    变量/方法:首字母小写,驼峰命名法,需要语义化,见名知意

    常量:全部大写字母,单词之间下划线隔开 要加个final修饰,不可改变

    关键字:Java官方用掉的名字

    数据类型

    数据类型分为基本数据类型和引用数据类型(复合数据类型)

    基本数据类型(四类八型)

    整数类型: byte 8 short 16 int(默认) 32 long 64 数字是位数

    浮点类型: float 32 单精度 double(默认) 64 双精度 float范围比long大因为它是小数的。浮点数不能用来表示精确的值,如货币

    字符型: char 只有这用单引号,其他基本都是双引号 char letter = ‘A’;

    布尔型 Boolean: true false(默认)

    引用数据类型

    它们是通过类来定义的。Java 中的引用数据类型包括:

    • 接口
    • 数组

    复合数据类型有无数种,自带方法和属性,如String、Scanner、Random等

    基本数据类型在内存中存储实际的值,而引用数据类型则存储对对象的引用(即内存地址)。在使用基本数据类型时,实际的值直接存储在变量中,而在使用引用数据类型时,变量存储的是对象的引用,对象本身存储在堆内存

    数据类型转换

    低的变高,是自动转换;高的变低必须强转,会精度损失

    浮点转整需要舍弃小数位

    byte到double 从低到高,byte 类型是 8 位,最大值为127,所以当 int 强制转换为 byte 类型时,值 128 时候就会导致溢出

    ------------------------------------>byte,short,char> int> long> float> double 
    int i =128;   
    byte b = (byte)i;
    

    float型转换为double型

    float f1=100.00f;
    Float F1=new Float(f1);
    double d1=F1.doubleValue();//F1.doubleValue()为Float类的返回double值型的方法
    

    简单类型的变量转换为相应的包装类,可以利用包装类的构造函数。即:Boolean(boolean value)、Character(char value)、Integer(int value)、Long(long value)、Float(float value)、Double(double value)

    而在各个包装类中,总有形为××Value()的方法,来得到其对应的简单类型数据。

    运算符

    • 算术运算符

      +、-、*、/、% 、++、-- (%取余5%2=1)

    • 关系运算符

      == 、!=、>、<、>=、<=

    • 位运算符

      & |(计算二进制的,用处少)

      7 二进制过程—> 7/2 =3 1 3/2=1 1 1/2= 1 0111 7的二进制结果倒着余数 111

      9 二进制过程—> 9/2=4 1 4/2=2 0 2/2=1 0 1/2= 1 1001 结果倒着余数 1001

      ​ 0001 7&9结果1 &必须2个是1才是1

    • 逻辑运算符

      &&(逻辑与,2真才真,也叫短路运算符,1假则不会继续下个判断了) 、||(逻辑或,1真就真)、 !(逻辑非)

    • 赋值运算符

      =、+=,-=…(c-=a 等价于 c=c-a 其他同理)

    • 条件运算符

      条件运算符也被称为三元运算符。该运算符有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量。

        int a = 10;
        int b = 20;
        int max = a < b ? b : a;  //10<20所以将b的值给max否则a,就是三元运算符
    

    条件

    Java 中的条件语句允许 程序 根据条件的不同执行不同的代码块

    if(布尔表达式 1){
       //如果布尔表达式 1的值为true执行代码
    }else if(布尔表达式 2){
       //如果布尔表达式 2的值为true执行代码
    }else if(布尔表达式 3){
       //如果布尔表达式 3的值为true执行代码
    }else {
       //如果以上布尔表达式都不为true执行代码
    }
    

    上面可以各种用

    switch case

    判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。

    switch(expression){
        case value :
           //语句
           break; //可选
        case value :
           //语句
           break; //可选
        //你可以有任意数量的case语句
        default : //可选
           //语句
    }
    
    public class Test {
       public static void main(String args[]){
          int i = 2;
          switch(i){
             case 0:
                System.out.println("0");
             case 1:
                System.out.println("1");
             case 2:
                System.out.println("2");
             default:
                System.out.println("default");
          }
       }
    }
    

    匹配成功后,从当前 case 开始,后续所有 case 的值都会输出

    2
    default

    如果i是6,都匹配不到则返回默认的default里的值,一般匹配到就break打断了

    循环

    Java中有三种主要的循环结构:

    • while 循环

      只要布尔表达式为 true,循环就会一直执行下去。

      while( 布尔表达式 ) {
        //循环内容
      }
      
    • do…while 循环

      do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。

      do {
             //代码语句
      }while(布尔表达式);
      
      
    • for 循环

      for循环执行的次数是在执行前就确定的

      for(初始化; 布尔表达式; 更新) {
          //代码语句
      }
      

    java5引入foreach—>数组的增强型 for 循环 数组a.for回车快速生成

    for(声明语句 : 表达式)
    {
       //代码句子
    }
    
    public class Demo1 {
        public static void main(String[] args) {
            int[] numbers = {10, 20, 30, 40, 50};
            for (int item : numbers) {
                System.out.println(item);
            }
        }
    }
    

    配合的关键字

    break主要用于停止,整个循环语句或者 switch 语句,循环语句后面的代码还会运行

    continue用于循环里面让程序跳过当前循环,立刻进入下一次的循环

    return用于返回方法类型指定的值也可以是对象,还能可以结束后面代码的执行

    public class Demo1 {
        public static void main(String[] args) {
            int[] numbers = {10, 20, 30, 40, 50};
            for (int item : numbers) {
    //            if (item == 10) {
    //                continue;//跳过当前满足的条件,继续循环          ---->20,30,40,50,哈哈
    //            }
                System.out.print(item);
                System.out.print(",");
                if (item == 10) {
    //                break;//满足条件时候跳出循环,循环后面的哈哈还是打印---->10,哈哈
                    return;//直接返回,不执行后续代码                  ---->10
                }
            }
            System.out.println("哈哈");
        }
    }
    

    总结

    for和while都被称为前置判断循环 do…while是后置判断循环

    while和do while都属于不确定次数的循环语句

    for 是属于确定次数的循环语句

    数组

    数组的创建

    入口函数那是推荐main(String[] args) 或者写main(String args[])

    声明

    dataType[] arrayRefVar;   // 首选的方法
    或
    dataType arrayRefVar[];  // 效果相同,但不是首选方法
    arrayRefVar = new dataType[arraySize];
    

    创建数组

    dataType[] arrayRefVar = new dataType[arraySize];  //动态声明
    dataType[] arrayRefVar = new dataType[]{value0, value1, ..., valuek};//用的少,使用1、3
    dataType[] arrayRefVar = {value0, value1, ..., valuek}; //静态声明方式
    

    一维数组

    public class Demo1 {
        public static void main(String[] args) {
            // 数组大小
            int size = 5;
            double[] myList = new double[size];
            myList[0] = 5.6;
            myList[1] = 4.5;
            myList[2] = 3.3;
            myList[3] = 13.2;
            myList[4] = 4.0;
            // 计算所有元素的总和
            double total = 0;
            for (int i = 0; i < size; i++) {
                total += myList[i];
            }
            System.out.println("总和为: " + total);
            // 查找最大元素
            double max = myList[0];
            for (int i = 1; i < myList.length; i++) {
                if (myList[i] > max) max = myList[i];
            }
            System.out.println("Max is " + max);
            System.out.println("-------------------");
            int[] arr = {1, 2, 3, 4, 5};
            for (int x : arr) {  //这里x只是变量名
                System.out.println(x);//如果里面还有一个循环int y :x
            }
        }
    }
    
    

    二维数组

    type[][] typeName = new type[typeLength1][typeLength2];
    

    type 可以为基本数据类型和复合数据类型,typeLength1 和 typeLength2 必须为正整数,typeLength1 为行数,typeLength2 为列数

    int[][] a = new int[2][3];
    

    a 可以看成一个两行三列的数组

    public class Demo1 {
        public static void main(String[] args) {
            String[][] s = new String[2][];
            s[0] = new String[2];
            s[1] = new String[3];
            s[0][0] = new String("Good");
            s[0][1] = new String("Luck");
            s[1][0] = new String("to");
            s[1][1] = new String("you");
            s[1][2] = new String("!");
    //        System.out.println(s[0][1]);//Lucky
            for (String[] strings : s) {
                for (String string : strings) {
                    System.out.print(string.concat("\t"));
                }
            }
        }
    }
    
    public class Demo1 {
        public static void main(String[] args) {
            String[] stu1 = {"张三", "Jx202211", "男", "22"};
            String[] stu2 = {"李四", "Jx202212", "女", "21"};
            String[] stu3 = {"王五", "Jx202213", "男", "25"};
            String[] stu4 = {"小六", "Jx202214", "女", "20"};
            String[][] stu = {stu1, stu2, stu3, stu4};
            for (int i = 0; i < stu.length; i++) {
                for (int j = 0; j < stu[i].length; j++) {
                    System.out.print(stu[i][j] + "\t");
                }
                System.out.println();
            }
        }
    }
    

    函数(方法)

    函数是一段具备特定功能的、高度封装的代码块

    函数声明:

    修饰符 返回值类型 方法名(参数类型 参数名){
        ...
        方法体
        ...
        return 返回值;
    }
    

    1、修饰符 public static 公开的 静态的
    2、返回值类 void 表返回值为null,就不需要return,其他都需要
    3、函数名 小驼峰命名
    4、参数列表
    5、方法体 要执行的代码块

    public class Demo1 {
        public static void main(String[] args) {
            Demo1.nPrintln("lucky", 2);//正常静态方法调用-->类名.方法名称() 
            Demo1 demo1 = new Demo1();//如果不是静态在类上需要new出来再.
            System.out.println("最大值是" + demo1.max(1, 2));
            System.out.println("最大值是" + demo1.max(11.2, 32.2));
            printMax(new double[]{1, 2, 3});//在本类中可以直接调用,无需类名
            printMax(new double[]{});
        }
    
        public static void nPrintln(String message, int n) {
            for (int i = 0; i < n; i++) {
                System.out.println(message);
            }
        }
    
        public int max(int num1, int num2) {
            return num1 > num2 ? num1 : num2;
        }
    
        public Double max(Double num1, Double num2) {
            return num1 > num2 ? num1 : num2;
        }
    
        public static void printMax(double... numbers) {//JDK 1.5 开始,Java支持传递同类型的可变参数给一个方法
            if (numbers.length == 0) {                  //在指定参数类型后加一个省略号...,传了个数组过来
                System.out.println("No argument passed");
                return;
            }
            double result = numbers[0];
            for (int i = 1; i < numbers.length; i++) {
                if (numbers[i] > result) {
                    result = numbers[i];
                }
            }
            System.out.println("The max value is " + result);
        }
    }
    

    形参与实参:函数声明里就是形参,而调用那里输入则是实参

    返回值:看声明里返回值类,void则没有返回值,如int则返回整型n,如果是类,返回一个对象类

    函数的递归:即函数里调用函数自己

    变量作用域:方法内声明的变量(局部变量),方法外不可用

    方法重载:同一类中方法名相同,参数数量和类型不同。构造方法(对象里的)就可以利用重载

    对象

    世界万物皆对象,对象的特点是属性、对象的行为是方法,对象的行为必须是自发的

    特征

    • 封装
    • 继承
    • 多态

    封装

    私有化属性并设置公有的get、set方法 IDEA右键—>生成—选择需要的

    封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问

    比如该类是公开的属性,那么外部new这个对象时候便可以直接.属性去修改,现在我们封装了它无法直接修改需要调用set方法去修改,比如年龄想修改1000岁是不正常的,我们便可以再set方法中加逻辑

    public class Lucky {
        private String name;
    
        public Lucky() {					//默认存在这个空构造
    
        }
    
        public Lucky(String name) {			//方法的重载
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override                 //方法的重写,原来是打印这个对象的引用地址
        public String toString() {//下面的值
            return "Lucky{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    
    public class Demo1 {
        public static void main(String[] args) {
            Lucky name = new Lucky("小维");
            System.out.println(name);
            Lucky name2 = new Lucky();
            name2.setName("小米");
            System.out.println(name2);
        }
    }
    

    结果:

    Lucky{name=‘小维’}
    Lucky{name=‘小米’}

    this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突

    构造函数

    是一个没有返回值,并且函数名和类型相同的函数,在对象实例化的一瞬间就会执行,利用构造函数的参数,对属性进行赋值

    继承

    继承就是子类继承父类的属性和方法 苹果是水果可以继承水果类 食草动物是动物可以继承动物类

    必须满足is-a关系 父类更通用 子类更具体

    关键字是extends 写在类名后面

    一个类只能继承一个抽象类, 继承不可滥用,牵一发而动全身,父类改变一次,其他全部受到影响,即耦合性过高,

    继承一般继承Java官方的类

    class 父类 {
    }
     
    class 子类 extends 父类 {
    }
    

    现在有3个类如下

    public class Penguin {
        private String name;
        private int id;
    
        public Penguin(String myName, int myid) {
            name = myName;
            id = myid;
        }
    
        public void eat() {
            System.out.println(name + "正在吃");
        }
    
        public void sleep() {
            System.out.println(name + "正在睡");
        }
    
        public void introduction() {
            System.out.println("大家好!我是" + id + "号" + name + ".");
        }
    }
    
    public class Mouse {
        private String name;
        private int id;
    
        public Mouse(String myName, int myid) {
            name = myName;
            id = myid;
        }
    
        public void eat() {
            System.out.println(name + "正在吃");
        }
    
        public void sleep() {
            System.out.println(name + "正在睡");
        }
    
        public void introduction() {
            System.out.println("大家好!我是" + id + "号" + name + ".");
        }
    }
    
    public class Demo1 {
        public static void main(String[] args) {
            Penguin penguin = new Penguin("企鹅", 1);
            penguin.eat();
            penguin.sleep();
            penguin.introduction();
            Mouse mouse = new Mouse("老鼠", 2);
            mouse.eat();
            mouse.sleep();
            mouse.introduction();
        }
    }
    

    会发现代码存在重复,导致代码量大且臃肿,而且维护性不高(主要表现是后期需要修改的时候,需要修改很多的代码,容易出错)

    要从根本上解决这两段代码的问题,就需要继承,将两段代码中相同的部分提取出来组成 一个父类

    public class Animal {
        private String name;
        private int id;
        public Animal(String myName, int myid) {
            name = myName;
            id = myid;
        }
        public void eat(){
            System.out.println(name+"正在吃");
        }
        public void sleep(){
            System.out.println(name+"正在睡");
        }
        public void introduction() {
            System.out.println("大家好!我是"         + id + "号" + name + ".");
        }
    }
    

    改造子类,extends单继承,子类只能有一个父类,可以多重继承比如a给b继承,b给c继承,没用过。子类不继承父类的构造器

    public class Penguin  extends Animal{
        public Penguin(String myName, int myid) {
            super(myName, myid);
        }
    }
    
    public class Mouse extends Animal {
        public Mouse(String myName, int myid) {
            super(myName, myid);//调用父类的构造并传入参数
        }
    }
    

    关键字 super :放在代码里 用来子类给父类的构造函数的参数传参,还能调用父类的方法 ,不过继承就有父方法了

    如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器

    继承关系下

    首先,会调用父类的构造函数。如果子类构造函数的第一行没有显式调用父类构造函数(通过 super()),则会自动调用父类的无参构造函数。如果父类没有无参构造函数,并且子类没有显式调用父类的其他构造函数,则编译器会报错

    然后,执行父类的构造函数体

    接着,再执行子类的构造函数。如果子类构造函数的第一行没有显式调用其他构造函数(通过 this()super()),则会自动调用父类的无参构造函数,然后执行子类的构造函数体

    最后,执行子类的构造函数体

    重写(Override)

    子类定义了一个与其父类中具有相同名称、参数列表和返回类型的方法,并且子类方法的实现覆盖了父类方法的实现。 即外壳不变,核心重写!

    父类的方法,子类写的一模一样,最终执行的是子类的方法

    重写规则:修饰符不能强于父类,返回值类型、方法名、参数列表必须一样

    重载(overloading)

    在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同

    多态

    多态指同一个事物能呈现出多种形态的能力 多态是继承的一种体现

    方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现

    多态就是同一个接口,使用不同的实例而执行不同操作

    多态存在的三个必要条件:

    • 继承
    • 重写
    • 父类引用指向子类对象:Parent p = new Child();

    AnimalT能呈现出多种形态的能力

    当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法

    public class Demo1 {
        public static void main(String[] args) {
            AnimalT a = new Lion();//父类引用指向子类对象,执行的是子类的方法,这就是多态   向上转型  
            a.eat();
            a.sleep();
        }
    }
    // 动物类 AnimalT.java
    abstract class AnimalT {
        abstract void eat();
        abstract void sleep();
    
    }
    // 狮子类 Lion.java
    class Lion extends AnimalT {
        public void eat() {
            System.out.println("狮子吃");
        }
        public void sleep() {
            System.out.println("狮子睡");
        }
    }
    // 老虎类 Tiger.java
    class Tiger extends AnimalT {
        public void eat() {
            System.out.println("老虎吃");
        }
        public void sleep() {
            System.out.println("老虎睡");
        }
    }
    
    class Animal {
        public void makeSound() {
            System.out.println("动物发出声音");
        }
    }
    
    class Dog extends Animal {
        @Override
        public void makeSound() {
            System.out.println("狗发出汪汪声");
        }
    }
    
    class Cat extends Animal {
        @Override
        public void makeSound() {
            System.out.println("猫发出喵喵声");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Animal animal1 = new Dog(); // 使用父类引用指向子类对象
            Animal animal2 = new Cat(); // 使用父类引用指向另一个子类对象
    
            animal1.makeSound(); // 调用被重写的方法,输出:狗发出汪汪声
            animal2.makeSound(); // 调用被重写的方法,输出:猫发出喵喵声
        }
    }
    

    这就是多态的体现,通过父类的引用调用被子类重写的方法

    接口

    接口并不是类,类描述对象的属性和方法。接口则包含类要实现的方法

    接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类

    接口:没有方法体的方法的集合

    • 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(JDK8后default也行,其他修饰符会报错)
    • JDK 1.8 以后,接口里可以有静态方法和方法体

    implements关键字

    使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)

    public interface A {              //定义A接口interface关键字
         void eat();
         void sleep();
    }
     
    public interface B {               //定义B接口
         void show();
    }
     
    public class C implements A,B {    //实现类 需要全部实现接口中的方法
    }
    

    有方法体的方法 被称为 实例方法

    没方法体的方法 被称为 抽象方法

    包装类

    所有的包装类**(Integer、Long、Byte、Double、Float、Short)**都是抽象类 Number 的子类

    这种由编译器特别支持的包装称为装箱,所以当内置数据类型被当作对象使用的时候,编译器会把内置类型装箱为包装类。相似的,编译器也可以把一个对象拆箱为内置类型。Number 类属于 java.lang 包

    public class Test{
       public static void main(String[] args){
          Integer x = 5; // x 被赋为整型值时,由于x是一个对象,所以编译器要对x进行装箱
          x =  x + 10;   //为了使x能进行加运算,所以要对x进行拆箱
          System.out.println(x); 
       }
    }
    

    修饰符

    访问控制修饰符

    Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。

    • default (无修饰): 本类、同一包的类可见
    • private : 私有的 能且仅能在本类中使用 注意:不能修饰类(private class Demo1 )错误
    • public : 对所有类可见。使用对象:类、接口、变量、方法
    • protected : 本类、子类、同一包的类可见 注意:不能修饰类(外部类)

    static

    static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量

    static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据

    它的特性:只会在类加载的时候执行一次。

    final

    final 表示"最后的、最终的"含义,变量一旦赋值后,不能被重新赋值。被 final 修饰的实例变量必须显式指定初始值

    final修饰类中的属性或者变量 无论属性是基本类型还是引用类型,final所起的作用都是变量里面存放的“值”不能变,这个值,对于基本类型来说,变量里面放的就是实实在在的值,而引用类型变量里面放的是个地址,所以用final修饰引用类型变量指的是它里面的地址不能变,并不是说这个地址所指向的对象或数组的内容不可以变,这个一定要注意

    final 修饰符通常和 static 修饰符一起使用来创建类常量。

    public class MyClass {
        public static int count = 0;                 //静态变量
        public static final int MAX_SIZE = 100;      // 使用大写蛇形命名法 常量
    }
    

    访问

    MyClass.count = 10; // 通过类名访问
    MyClass obj = new MyClass();
    obj.count = 20; // 通过实例名访问
    

    final 属性 声明变量时可以不赋值,而且一旦赋值就不能被修改了,用来new的那个对象里有final修饰的属性那个属性必须赋值

    final 方法 可以被子类继承,但是不能被子类重写。声明 final 方法的主要目的是防止该方法的内容被修改

    final 类 不能被继承

    abstract(抽象类)

    抽象类不能用来实例化对象

    一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误

    抽象类可以包含抽象方法和非抽象方法

    abstract class Caravan{  //被abstract修饰就是抽象类
       private double price;
       private String model;
       private String year;
       public abstract void goFast(); //抽象方法
       public abstract void changeColor();
    }
    

    抽象方法是一种没有任何实现的方法,该方法的具体实现由子类提供

    抽象方法不能被声明成 final 和 static

    如果一个类包含抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法

    继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也必须声明为抽象类

    构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法

    抽象方法的声明以分号结尾,例如:public abstract sample();

    public abstract class SuperClass{
        abstract void m(); //抽象方法
    }
     
    class SubClass extends SuperClass{
         //实现抽象方法
          void m(){
              .........
          }
    }
    

    synchronized

    synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符。

    public synchronized void showDetails(){
    .......
    }
    

    枚举类

    枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一年的 12 个月份,一个星期的 7 天,方向有东南西北等—>场景:颜色(红黄蓝绿…)、星期、反射做多个oss桶时候

    常量类是指一组声明为静态的、不可改变的常量变量,它们通常用于定义一些全局性的常量,如数学常数π、还有一些不变的值,项目中必定有一个常量类,final关键字,表示这些变量不能被修改—> 场景:分页的当前页、限制页数、返回的数据成功、失败…

    Java 枚举类使用 enum 关键字来定义,各个常量使用逗号 , 来分割

    enum Color {
        RED, GREEN, BLUE;
        private Color()    // 构造函数只能使用 private 访问修饰符,所以外部无法调用
        {
            System.out.println("Constructor called for : " + this.toString());
        }
        public void colorInfo() {//枚举既可以包含具体方法,也可以包含抽象方法。 如果枚举类具有抽象方法,则枚举类的每个实例都必须实现它
            System.out.println("枚举的方法");
        }
    }
    

    每个枚举都是通过 Class 在内部实现的,且所有的枚举值都是 public static final 的,所以可以 类名.名称

    • values() 返回枚举类中所有的值。
    • ordinal()方法可以找到每个枚举常量的索引,就像数组索引一样。
    • valueOf()方法返回指定字符串值的枚举常量。
    public class Demo1 {
        public static void main(String[] args) {
            Color c1 = Color.RED;
            System.out.println(c1);
            for (Color myVar : Color.values()) {
                System.out.println(myVar);
            }
            // ------------------------------------------------
            Color myVar = Color.BLUE;
            switch (myVar) {
                case RED:
                    System.out.println("红色");
                    break;
                case GREEN:
                    System.out.println("绿色");
                    break;
                case BLUE:
                    System.out.println("蓝色");
                    break;
            }
            // ------------------------------------------------
            Color[] arr = Color.values();
            // 迭代枚举
            for (Color col : arr) {
                // 查看索引
                System.out.println(col + " at index " + col.ordinal());
            }
            // 使用 valueOf() 返回枚举常量,不存在的会报错 IllegalArgumentException
            System.out.println(Color.valueOf("RED"));
            // ------------------------------------------------
            Color green = Color.GREEN;//下面2个结果一样
            green.colorInfo();
            Color red = Color.RED;
            red.colorInfo();
        }
    }
    

    工作中的写法1

    public enum ErrorCode {
        OK(0) {
            public String getDescription() {
                return "成功";
            }
        },
        ERROR_A(100) {
            public String getDescription() {
                return "错误A";
            }
        },
        ERROR_B(200) {
            public String getDescription() {
                return "错误B";
            }
        };                            //分号
        private int code;
        // 构造方法:enum的构造方法只能被声明为private权限或不声明权限
        private ErrorCode(int number) { // 构造方法
            this.code = number;
        }
        public int getCode() { // 普通方法
            return code;
        } // 普通方法
        public abstract String getDescription(); // 抽象方法
    }
    

    写法2 效果和调用一样

    public enum ErrorCodeEn {
        OK(0, "成功"),
        ERROR_A(100, "错误A"),
        ERROR_B(200, "错误B");
        ErrorCodeEn(int number, String description) {
            this.code = number;
            this.description = description;
        }
        private int code;
        private String description;
        public int getCode() {
            return code;
        }
        public String getDescription() {
            return description;
        }
    }
    
    public class Demo1 {
        public static void main(String[] args) {
            // 获取枚举常量的值
            System.out.println(ErrorCodeEn.OK.getCode()); // 输出: 0
            System.out.println(ErrorCodeEn.ERROR_A.getCode()); // 输出: 100
            System.out.println(ErrorCodeEn.ERROR_B.getCode()); // 输出: 200
            // 获取枚举常量的描述
            System.out.println(ErrorCodeEn.OK.getDescription()); // 输出: 成功
            System.out.println(ErrorCodeEn.ERROR_A.getDescription()); // 输出: 错误A
            System.out.println(ErrorCodeEn.ERROR_B.getDescription()); // 输出: 错误B
    
        }
    }
    

    补充

    面向对象与面向过程区别

    面向过程:只关注事情本身的完成,不关注谁去做,就像大象塞进冰箱,不管是谁把冰箱打开,谁把大象弄进去

    面向对象:更多关注 谁去做事情 各有各的好处

    对象的生命周期

    对象的出生:一旦被声明被赋值之后 对象即出现

    对象的销毁:当该对象没有被指向 就会被自动销毁

    String a;这是空,没有对象,所以没有出生和销毁

    IO流

    IO 流:按照流动的方向,以内存为基准,分为输入 input 和输出 output ,即流向内存是输入流,流出内存的输出流

    (1)明确要操作的数据是数据源还是数据目的(也就是要读还是要写)
    (2)明确要操作的设备上的数据是字节还是文本
    (3)明确数据所在的具体设备
    (4)明确是否需要额外功能(比如是否需要转换流、高效流等)

    输入流(读数据 硬盘---->内存)、输出流(写数据 内存—>硬盘)

    分类:

    1.字节流:字节流又分为字节输入流、字节输出流 2.字符流:字符流由分为字符输入流、字符输出流

    字符流的由来:因为数据编码的不同,字节流直接读中文会乱码 字符流 = 字节流 + 编码表

    数据流向内存就是输入流,流出内存就是输出流,根据数据的类型分为

    字节流和字符流,如名字的为单位

    字节流对应的输入流 InputStream 输出流 OutputStream

    字符流对应的输入流 Reader 输出流 Writer

    超类(父类)以这四个名称结尾都是它的子类

    比如常见的 FileInputStream 文件输入流

    1 个字符=2 个字节

    字节流适合读取视频、音乐、图片等二进制文件,字符流比较适合读取纯文本文件

    字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据

    File 类

    java.io.File 类是专门对文件进行操作的类,只能对文件本身进行操作,不能对文件进行读和写也就是输入和输出

    File 类构造方法不会给你检验这个文件或文件夹是否真实存在,因此无论该路径下是否存在文件或者目录,都不影响 File 对象的创建。

    下面一个测试类

    package com.nwa;
    
    import org.junit.Test;
    
    
    import java.io.*;
    
    /**
     * @Author Lucky友人a
     * @Date 2023/8/10 -10:34
     */
    public class FileDemo {
        @Test
        public void fun1() throws IOException {
            File f = new File("C:\\Users\\FF\\Desktop\\1.txt");  //就算文件1.txt不存在也不影响file对象的创建
            if (!f.exists()) {
                    System.out.println("是否创建:"+f.createNewFile()); // true 如果没有文件则创建并返回true
            }
            System.out.println("是否创建:"+f.createNewFile());  //已经存在,所以就false了
            System.out.println("文件绝对路径:"+f.getAbsolutePath());//文件绝对路径:C:\Users\FF\Desktop\1.txt
            System.out.println("文件构造路径:"+f.getPath());        //文件构造路径:C:\Users\FF\Desktop\1.txt
            System.out.println("文件名称:"+f.getName());          //文件名称:1.txt
            System.out.println("文件长度:"+f.length()+"字节");
            // 判断是文件还是目录
            System.out.println("文件:"+f.isFile());
            System.out.println("目录:"+f.isDirectory());
            //一个路径下全部文件名,先将字符串转目录
    //        String path = "D:\\workspace";
    //        File file = new File(path);
    //        printFile(file);
        }
    //结果1   传进的file不一样结果不一样,如果是绝对位置那么构造啥的都是绝对的
    //    是否创建:false
    //    文件绝对路径:C:\Users\FF\Desktop\1.txt
    //    文件构造路径:C:\Users\FF\Desktop\1.txt
    //    文件名称:1.txt
    //    文件长度:0字节
    //    文件:true
    //    目录:false
    
    
    //结果2 如果是直接1.txt则会相对这个项目来创建这个文件
    //    是否创建:true
    //    是否创建:false
    //    文件绝对路径:E:\LuckyWorckSpace\lucky_api\1.txt
    //    文件构造路径:1.txt
    //    文件名称:1.txt
    //    文件长度:0字节
    //    文件:true
    //    目录:false
        @Test
        public void testDemo2() {   //目录的创建等,使用相对这个项目下的目录来测试了
            // 目录的创建
            File f2= new File("newDira");
    //        System.out.println("是否存在:"+f2.exists());// false
    //        System.out.println("是否创建:"+f2.mkdir());	//  这个是创建的意思,并返回true
    //        System.out.println("是否存在:"+f2.exists());// true
            // 创建多级目录
    //        File f3= new File("newDira\\newDirb");
    //        System.out.println(f3.mkdir());// false,没有加s指南创建单层的目录
            File f4= new File("newDira\\newDirb");
      //      System.out.println(f4.mkdirs());// true,可以创建多级别的目录
    
            // 文件和目录的删除  delete方法,如果此File表示目录,则目录必须为空才能删除。
          //  System.out.println(f2.delete());// true
       //     System.out.println(f4.delete());// false如果是删除多层目录只能删除最底层的比如这个的newDirb目录,外newDira没有删掉
        }
    
        @Test
        public void demo3() {
            File file = new File("E:\\other\\study\\学习sp\\实用篇");
            printFile(file);
        }
        public  static void printFile(File file) {
    //        //获取当前目录下的文件以及文件夹的名称。
    //        File[] files = file.listFiles();
    //        for (File a:files) {
    //
    //            if (a.isFile()) {
    //                System.out.println( a.getName());
    //            }else {
    //                printFile(a);
    //            }
    //        }
    
    //        //下面的只获取一层,上面是里面全部获取
    //        String[] names = file.list();
    //        for(String name : names){
    //            System.out.println(name);
    //        }
    //        //获取当前目录下的文件以及文件夹对象,只要拿到了文件对象,那么就可以获取更多信息
    //        File[] files = file.listFiles(); //listFiles指定的必须是目录。否则容易引发返回数组为null,出现NullPointerException异常
    //        for (File fi : files) {
    //            System.out.println(fi);
    //        }
    
    //        递归全部
            //1、判断传入的是否是目录
            if(!file.isDirectory()){
                //不是目录直接退出
                return;
            }
            //已经确保了传入的file是目录
            File[] files = file.listFiles();
            //遍历files
            for (File f: files) {
                //如果该目录下文件还是个文件夹就再进行递归遍历其子目录
                if(f.isDirectory()){
                    //递归
                    printFile(f);
                }else {
                    //如果该目录下文件是个文件,则打印对应的名字
                    System.out.println(f.getName());
                }
    
            }
        }
    
    
        public static void demo2(){
             //从d盘下的a.txt文件拷贝到另个盘下
            try {
                File file1 = new File("D:\\workspace\\a.txt");//这是源文件
                long flen=file1.length();
                System.out.println("源文件的大小是"+flen+"字节");
                FileInputStream fis = new FileInputStream(file1);
                File file2 = new File("D:\\workspace\\b.txt");//这是复制到的地方
                FileOutputStream fos = new FileOutputStream(file2);
                byte[] bytes = new byte[1024]; //这是1兆1兆传
                int len = 0;
                long readSize=0;
                while ((len = fis.read(bytes)) != -1) {//-1就是最后一个结束
                    fos.write(bytes,0,len); //比如一个文件是1024*8+244,那么len就是244
                    fos.flush();//强制输出,推送数据
                    readSize+=len;
                    if (readSize== flen) {
                        break;
                    }
                }
                System.out.println("读的大小"+readSize+"字节");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        public static void demo1() {
            File file = new File("E:\\1.txt");
            File file1 = new File("E:\\222.txt");
            try {
                FileInputStream fis = new FileInputStream(file);
                FileOutputStream fos = new FileOutputStream(file1);
                BufferedInputStream bis = new BufferedInputStream(fis);
                byte[] bytes = new byte[1024];
                while (bis.read(bytes) != -1) {
                    fos.write(bytes);
                    fos.flush();
                    System.out.println("aaaa");
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    }
    
    

    FileOutputStream

    FileOutputStream outputStream = new FileOutputStream("abc.txt");
    

    这行代码做了下面的事情
    1、调用系统功能去创建文件【输出流对象才会自动创建】
    2、创建outputStream对象
    3、把foutputStream对象指向这个文件

    创建输出流对象的时候,系统会自动去对应位置创建对应文件,而创建输出流对象的时候,文件不存在则会报 FileNotFoundException 异常,也就是系统找不到指定的文件异常。

    当你创建一个流对象时,必须直接或者间接传入一个文件路径。比如现在我们创建一个 FileOutputStream 流对象,在该路径下,如果没有这个文件,会创建该文件。如果有这个文件,会清空这个文件的数据

    为什么是输入流呢

    1、因为流是相对于内存来说的,现在 abc.txt 就是要保存到磁盘里面的文本,就是说从内存---->磁盘,那必须是输出流,用 FileWrite 和 FileOutputStream 都可以

    2、传入路径时候是它的一种构造方法,不会继续写到文本中,所以用它的另外的构造函数即可解决这个问题。

    • public FileOutputStream(File file, boolean append) 一般不需要用这个,因为文件创建,输出流自动会帮我们生成,没必要多此一举暂时

    • public FileOutputStream(String name, boolean append) true 表示追加数据

    Windows 系统里,每行结尾是 回车+换行 ,即\r\n;
    Unix 系统里,每行结尾只有 换行 ,即\n;
    Mac 系统里,每行结尾是 回车 ,即\r。从 Mac OS X 开始与 Linux 统一。

    FileInputStream

    流进内存的,输入流

    1、 FileInputStream(File file): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File 对象 file 命名。
    2、 FileInputStream(String name): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name 命名。

    当你创建一个输入流对象时,必须传一个文件路径。该路径下,如果没有该文件,会抛出 FileNotFoundException

    使用字节数组读取:read(byte[] b) 效率更高

                int len = 0 ;
                byte[] bys = new byte[1024];
                while ((len = inputStream.read(bys)) != -1) {
                    System.out.println(new String(bys,0,len));//len输出有效的字节数
    

    Reader

    字符输入流的所有类的超类 输入流

    FileWriter

    写出字符到文件的便利类 输出流

    //关闭资源时,与 FileOutputStream 不同。 如果不关闭,数据只是保存到缓冲区,并未保存到文件。

    // fw.close();

    关闭 close 和刷新 flush
    因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要 flush 方法了。

    flush :刷新缓冲区,流对象可以继续使用。清空缓冲区的数据流
    close:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

    缓冲流

    1、使用了底层流对象从具体设备上获取数据,并将数据存储到缓冲区的数组内。
    2、通过缓冲区的 read()方法从缓冲区获取具体的字符数据,这样就提高了效率。
    3、如果用 read 方法读取字符数据,并存储到另一个容器中,直到读取到了换行符时,将另一个容器临时存储的数据转成字符串返回,就形成了 readLine()功能。

    也就是说在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统 IO 次数,从而提高读写的效率。

    缓冲书写格式为 BufferedXxx,按照数据类型分类:

    字节缓冲流:BufferedInputStream,BufferedOutputStream
    字符缓冲流:BufferedReader,BufferedWriter
    构造方法
    public BufferedInputStream(InputStream in) :创建一个新的缓冲输入流,注意参数类型为 InputStream。
    public BufferedOutputStream(OutputStream out): 创建一个新的缓冲输出流,注意参数类型为 OutputStream。

    BufferedReader:public String readLine(): 读一行数据。 读取到最后返回 null,就这个特别一点,判断条件都需要修改了
    BufferedWriter:public void newLine(): 换行,由系统属性定义符号。

    转换流

    简单一点的说就是:

    编码:字符(能看懂的)–字节(看不懂的)

    解码:字节(看不懂的)–>字符(能看懂的)

    String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组
    byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组
    
    编码:把看得懂的变成看不懂的
    String -- byte[]
    
    解码:把看不懂的变成看得懂的
    byte[] -- String
    

    字符集 Charset:也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。

    在 java 开发工具 IDEA 中,使用 FileReader 读取项目中的文本文件。由于 IDEA 的设置,都是默认的 UTF-8 编码,所以没有任何问题。但是,当读取 Windows 系统中创建的文本文件时,由于 Windows 系统的默认是 GBK 编码,就会出现乱码。

    转换流 java.io.InputStreamReader,是 Reader 的子类,从字面意思可以看出它是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。

    构造方法
    InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。
    InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。

    构造代码如下:

    InputStreamReader isr = new InputStreamReader(new FileInputStream("in.txt"));
    InputStreamReader isr2 = new InputStreamReader(new FileInputStream("in.txt") , "GBK");
    

    OutputStreamWriter同理

    案例 1

    package com.nwa;
    
    import org.junit.Test;
    
    
    import java.io.*;
    
    /**
     * @Author Lucky友人a
     * @Date 2023/8/10 -10:34
     */
    public class FileDemo {
        @Test
        public void fun1() throws IOException {
            File f = new File("C:\\Users\\FF\\Desktop\\1.txt");  //就算文件1.txt不存在也不影响file对象的创建
            if (!f.exists()) {
                    System.out.println("是否创建:"+f.createNewFile()); // true 如果没有文件则创建并返回true
            }
            System.out.println("是否创建:"+f.createNewFile());  //已经存在,所以就false了
            System.out.println("文件绝对路径:"+f.getAbsolutePath());//文件绝对路径:C:\Users\FF\Desktop\1.txt
            System.out.println("文件构造路径:"+f.getPath());        //文件构造路径:C:\Users\FF\Desktop\1.txt
            System.out.println("文件名称:"+f.getName());          //文件名称:1.txt
            System.out.println("文件长度:"+f.length()+"字节");
            // 判断是文件还是目录
            System.out.println("文件:"+f.isFile());
            System.out.println("目录:"+f.isDirectory());
            //一个路径下全部文件名,先将字符串转目录
    //        String path = "D:\\workspace";
    //        File file = new File(path);
    //        printFile(file);
        }
    //结果1   传进的file不一样结果不一样,如果是绝对位置那么构造啥的都是绝对的
    //    是否创建:false
    //    文件绝对路径:C:\Users\FF\Desktop\1.txt
    //    文件构造路径:C:\Users\FF\Desktop\1.txt
    //    文件名称:1.txt
    //    文件长度:0字节
    //    文件:true
    //    目录:false
    
    
    //结果2 如果是直接1.txt则会相对这个项目来创建这个文件
    //    是否创建:true
    //    是否创建:false
    //    文件绝对路径:E:\LuckyWorckSpace\lucky_api\1.txt
    //    文件构造路径:1.txt
    //    文件名称:1.txt
    //    文件长度:0字节
    //    文件:true
    //    目录:false
        @Test
        public void testDemo2() {   //目录的创建等,使用相对这个项目下的目录来测试了
            // 目录的创建
            File f2= new File("newDira");
    //        System.out.println("是否存在:"+f2.exists());// false
    //        System.out.println("是否创建:"+f2.mkdir());	//  这个是创建的意思,并返回true
    //        System.out.println("是否存在:"+f2.exists());// true
            // 创建多级目录
    //        File f3= new File("newDira\\newDirb");
    //        System.out.println(f3.mkdir());// false,没有加s指南创建单层的目录
            File f4= new File("newDira\\newDirb");
      //      System.out.println(f4.mkdirs());// true,可以创建多级别的目录
    
            // 文件和目录的删除  delete方法,如果此File表示目录,则目录必须为空才能删除。
          //  System.out.println(f2.delete());// true
       //     System.out.println(f4.delete());// false如果是删除多层目录只能删除最底层的比如这个的newDirb目录,外newDira没有删掉
        }
    
        @Test
        public void demo3() {
            File file = new File("E:\\other\\study\\学习sp\\实用篇");
            printFile(file);
        }
        public  static void printFile(File file) {
    //        //获取当前目录下的文件以及文件夹的名称。
    //        File[] files = file.listFiles();
    //        for (File a:files) {
    //
    //            if (a.isFile()) {
    //                System.out.println( a.getName());
    //            }else {
    //                printFile(a);
    //            }
    //        }
    
    //        //下面的只获取一层,上面是里面全部获取
    //        String[] names = file.list();
    //        for(String name : names){
    //            System.out.println(name);
    //        }
    //        //获取当前目录下的文件以及文件夹对象,只要拿到了文件对象,那么就可以获取更多信息
    //        File[] files = file.listFiles(); //listFiles指定的必须是目录。否则容易引发返回数组为null,出现NullPointerException异常
    //        for (File fi : files) {
    //            System.out.println(fi);
    //        }
    
    //        递归全部
            //1、判断传入的是否是目录
            if(!file.isDirectory()){
                //不是目录直接退出
                return;
            }
            //已经确保了传入的file是目录
            File[] files = file.listFiles();
            //遍历files
            for (File f: files) {
                //如果该目录下文件还是个文件夹就再进行递归遍历其子目录
                if(f.isDirectory()){
                    //递归
                    printFile(f);
                }else {
                    //如果该目录下文件是个文件,则打印对应的名字
                    System.out.println(f.getName());
                }
    
            }
        }
    
    
        public static void demo2(){
             //从d盘下的a.txt文件拷贝到另个盘下
            try {
                File file1 = new File("D:\\workspace\\a.txt");//这是源文件
                long flen=file1.length();
                System.out.println("源文件的大小是"+flen+"字节");
                FileInputStream fis = new FileInputStream(file1);
                File file2 = new File("D:\\workspace\\b.txt");//这是复制到的地方
                FileOutputStream fos = new FileOutputStream(file2);
                byte[] bytes = new byte[1024]; //这是1兆1兆传
                int len = 0;
                long readSize=0;
                while ((len = fis.read(bytes)) != -1) {//-1就是最后一个结束
                    fos.write(bytes,0,len); //比如一个文件是1024*8+244,那么len就是244
                    fos.flush();//强制输出,推送数据
                    readSize+=len;
                    if (readSize== flen) {
                        break;
                    }
                }
                System.out.println("读的大小"+readSize+"字节");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        public static void demo1() {
            File file = new File("E:\\1.txt");
            File file1 = new File("E:\\222.txt");
            try {
                FileInputStream fis = new FileInputStream(file);
                FileOutputStream fos = new FileOutputStream(file1);
                BufferedInputStream bis = new BufferedInputStream(fis);
                byte[] bytes = new byte[1024];
                while (bis.read(bytes) != -1) {
                    fos.write(bytes);
                    fos.flush();
                    System.out.println("aaaa");
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    }
    
    

    案例 2

    package com.nwa;
    
    import org.junit.Test;
    import org.omg.CORBA.PUBLIC_MEMBER;
    
    import java.io.*;
    
    /**
     * @Author Lucky友人a
     * @Date 2023/8/10 -14:14
     */
    public class IoDemo {
        @Test
        public void demo1() throws IOException {
            //public void write(int b)
            //public void write(byte[] b)
            //public void write(byte[] b,int off,int len)  //从`off`索引开始,`len`个字节
            //构造方法中加入true即可追加数据,否则就是清空了
            FileOutputStream fos = new FileOutputStream("a.txt", true);//输出流,如果没有文件则帮忙创,有的话清空里面数据
            fos.write(97);//对于内存里流向本地磁盘,所以是输出流,而且会帮忙创建文件,并写入数据,所以才会清空
            fos.write(("我要吃汉堡").getBytes());
            fos.close();
            //a我要吃汉堡    97字节对于的是小写的a,字符串这个是转字节了
            FileWriter fileWriter = new FileWriter("b.txt");
            fileWriter.write("ss");//这个可以直接写入
            fileWriter.close();
    
            //写出指定长度字节数组:write(byte[] b, int off, int len) ,每次写出从off索引开始,len个字节
            // 使用文件名称创建流对象
            FileOutputStream fos2 = new FileOutputStream("a2.txt");
            // 字符串转换为字节数组
            byte[] b = "abcde".getBytes();
            // 写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。
            fos2.write(b, 2, 2);
            // 关闭资源
            fos2.close();
        }
    
        @Test
        public void delTxt() {
            new File("a.txt").delete();
        }
    
        @Test
        public void arrDemo() throws IOException {
            // 使用文件名称创建流对象
            FileOutputStream fos = new FileOutputStream("fos.txt");
            // 定义字节数组
            byte[] words = {97, 98, 99, 100, 101};
            // 遍历数组
            for (int i = 0; i < words.length; i++) {
                // 写出一个字节
                fos.write(words[i]);
                // 写出一个换行, 换行符号转成数组写出
                fos.write("\r\n".getBytes());
            }
            // 关闭资源
            fos.close();
        }
    
        @Test
        public void inputS() throws IOException {
            // 使用File对象创建流对象
            File file = new File("a2.txt");//这个文本中只有cd2个字符
            FileInputStream fis = new FileInputStream(file);//我把a.txt删了它就找不到了报错
    //        int read = fis.read();
    //        System.out.println((char)read);//不加char的话会转数字那种99---c
    //        int read1 = fis.read();//继续读取下一个字符
    //        System.out.println((char)read1);
    //        int read2 = fis.read();//如果是最后一个字符,它会返回-1,通过-1知道到底了
    //        System.out.println(read2);
    //        fis.close();
            //改进版1
    //        int b;
    //        while ((b = fis.read()) != -1) {
    //            System.out.println((char)b);
    //        }
    //        fis.close();
            //改进版2将文本里的值变成的abced,一次读取2个,结果出现了abcded
            //1 a  b  2  c  d  3e  d  因为没替换就流着了,要解决一下改进3
            // 定义变量,作为有效个数
    //        int len;
    //        // 定义字节数组,作为装字节数据的容器
    //        byte[] b = new byte[2];
    //        // 循环读取
    //        while (( len= fis.read(b))!=-1) {
    //            // 每次读取后,把数组变成字符串打印
    //            System.out.println(new String(b));
    //        }
            // 关闭资源
            //  fis.close();
    //        改进3
            int len;
            // 定义字节数组,作为装字节数据的容器
            byte[] b = new byte[2];
            // 循环读取
            while ((len = fis.read(b)) != -1) {
                // 每次读取后,把数组变成字符串打印
                System.out.println(new String(b, 0, len));//len是每次读取有效的个数
            }
            // 关闭资源
            fis.close();
        }
    
        @Test
        public void copyPic() throws IOException {//将本地图片复制到项目下面
            FileInputStream fis = new FileInputStream("C:\\Users\\FF\\Desktop\\6.png");//输入流到内存
            FileOutputStream fos = new FileOutputStream("1.png");//内存输出到项目下面
            byte[] b = new byte[1024];
            int len;
            while ((len = fis.read(b)) != -1) {
                fos.write(b, 0, len);
            }
            fos.close();
            fis.close();
        }
    
        @Test
        public void readI() throws IOException {
            FileInputStream fis = new FileInputStream("1.txt");//输入流。文本中是中文你是大聪明,正常字节流去解析会乱码
            int len;
            byte[] bytes = new byte[1024];
            while ((len = fis.read(bytes)) != -1) {
                System.out.println((char) len);  //乱码
                System.out.print(new String(bytes, 0, len));//String里自带了utf8解码所以可以。不过比较麻烦直接字符流解决
            }
            //下面用字符流
            FileReader fr = new FileReader("1.txt");
            int len2;
            while ((len2 = fr.read()) != -1) {
                System.out.print((char) len2);
            }
        }
    
        @Test
        public void copyText() throws  IOException{
            FileWriter fileWriter = new FileWriter("66.md");
            FileReader fileReader = new FileReader("E:\\后端代码接收解析.md");
            char[] c=new char[1024];
            int len;
            while ((len = fileReader.read(c)) != -1) {
                fileWriter.write(c, 0, len);
    
            }
            fileWriter.flush();//清空缓冲区的数据流
            fileWriter.close();
            fileReader.close();
        }
        //下面开始测试缓存流的速度效率,1是正常,2是加入缓存
    
        @Test
        public void Buff1() throws  IOException{
            long start = System.currentTimeMillis();
            FileOutputStream fos = new FileOutputStream("ps2015.zip");
            FileInputStream fis = new FileInputStream("E:\\other\\装机必备软件\\必备软件\\ps2015.zip");
            byte[] bytes = new byte[1024];
            int len;
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
            fis.close();
            fos.close();
            // 记录结束时间
            long end = System.currentTimeMillis();
            System.out.println("普通流复制时间:"+(end - start)+" 毫秒");//33000
        }
        @Test
        public void Buff2() throws  IOException{
            long start = System.currentTimeMillis();
            BufferedOutputStream fos =new   BufferedOutputStream(new FileOutputStream("ps2015.zip")) ;
            BufferedInputStream fis =new BufferedInputStream(new FileInputStream("E:\\other\\装机必备软件\\必备软件\\ps2015.zip")) ;
            byte[] bytes = new byte[1024];
            int len;
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
            fis.close();
            fos.close();
            // 记录结束时间
            long end = System.currentTimeMillis();
            System.out.println("缓冲流复制时间:"+(end - start)+" 毫秒");//缓冲流复制时间:4314 毫秒
        }
    
        @Test
        public void BuffRead() throws IOException {
            BufferedReader br = new BufferedReader(new FileReader("b.txt"));//       两个黄鹂鸣翠柳,一行白鹭上青天。 窗含西岭千秋雪,门泊东吴万里船。
            System.out.println(br.readLine()); // 读取一行的
            String len=null;
            while ((len = br.readLine()) != null) {
                System.out.println((len));
            }
            br.close();
        }
    
        @Test
        public void transform() throws IOException{
            // 定义文件路径,文件为gbk编码
            String FileName = "C:\\Users\\FF\\Desktop\\1.txt";
            // 创建流对象,默认UTF8编码
            InputStreamReader isr = new InputStreamReader(new FileInputStream(FileName));
            // 创建流对象,指定GBK编码
            InputStreamReader isr2 = new InputStreamReader(new FileInputStream(FileName) , "GBK");
            // 定义变量,保存字符
            int read;
            // 使用默认编码字符流读取,乱码
            while ((read = isr.read()) != -1) {
                System.out.print((char)read);
            }
            isr.close();
    
            // 使用指定编码字符流读取,正常解析
            while ((read = isr2.read()) != -1) {
                System.out.print((char)read); //如果这个txt默认是ANSI编码就需要GBK就不会乱码,如果本身就utf就不需要编码了
            }
            isr2.close();
        }
    
    
    }
    
    

    异常处理

    异常处理是一种重要的编程概念,用于处理程序执行过程中可能出现的错误或异常情况

    必须捕获的异常,包括Exception及其子类,但不包括RuntimeException及其子类,这种类型的异常称为Checked Exception

    不需要捕获的异常,包括Error及其子类,RuntimeException及其子类

    • 数值类型的格式错误------------NumberFormatException
    • 要打开的文件不存在------------FileNotFoundException
    • 空指针------------NullPointerException------------对某个null的对象调用方法或字段
    • 数组索引越界------------ArrayIndexOutOfBoundsException
    • 数据库表不存在
    • 向方法传递了一个不合法或不正确的参数
    • 无法加载某个Class------------NoClassDefFoundError
    • 栈溢出------------StackOverflowError

    错误: 错误不是异常,而是脱离程序员控制的问题,错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的

    所有的异常类是从 java.lang.Exception 类继承的子类。

    Exception 类是 Throwable 类的子类。除了Exception类外,Throwable还有一个子类Error

    异常类有两个主要的子类:IOException 类和 RuntimeException 类

    捕获异常

    如果不捕获异常,就需要抛出异常,直到有人捕获或者最高一级

    使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。ctrl+alt+t

    throws 是写在类那里--------------------throw 是直接在方法里面抛出

    try/catch代码块中的代码称为保护代码,使用 try/catch 的语法如下:

    try
    {
       // 程序代码
    }catch(ExceptionName e1)
    {
       //Catch 块
    }
    
    

    throw 关键字用于在代码中抛出异常,而 throws 关键字用于在方法声明中指定可能会抛出的异常类型

    当方法内部throws抛出指定类型的异常时,该异常会被传递给调用该方法的代码,并在该代码中处理异常。

    public class Demo1 {
        public static void main(String[] args) {
    //        Scanner scanner = new Scanner(System.in);
    //        scanner = null;
    //        scanner.next();                                               //空指针java.lang.NullPointerException
    
    //        int[] a = new int[]{1, 2};
    //        System.out.println(a[2]);                                     //数组索引越界java.lang.ArrayIndexOutOfBoundsException
    
    //        try {
    //            System.out.println(11 / 0);                               //0不能为除数java.lang.ArithmeticException异常
    //        } catch (ArithmeticException e) {
    //            System.out.println("捕获到了0不能为除数的异常");//这里抛出了运行时异常
    //        } catch (Exception e) {//最大异常,上面捕获了下面就捕获了
    //            throw new RuntimeException(e); //这里抛出了运行时异常
    //        } finally {
    //            System.out.println("这里必运行,一般用来关闭");
    //        }
    
    //        checkNumber(-1);//非法参数异常IllegalArgumentException
            try {
                //  readFile("D:\\1.txt");//去d盘新建1.txt,内容随便写点
                readFile("D:\\1.txt");//没找到就会有异常
                System.out.println("找到了");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
    
        }
    
        public static void checkNumber(int num) {
            if (num < 0) {
                throw new IllegalArgumentException("Number must be positive");//当代码执行到某个条件下无法继续正常执行时,可以使用 throw 关键字抛出异常,以告知调用者当前代码的执行状态
            }
        }
    
        public static void readFile(String filePath) throws IOException {// 包含了文件没找到异常,如果还有其他异常,隔开继续写
            BufferedReader reader = new BufferedReader(new FileReader(filePath));
            String line = reader.readLine();
            while (line != null) {
                System.out.println(line);
                line = reader.readLine();
            }
            reader.close();
        }
    }
    
    

    JDK7 之后,Java 新增的 try-with-resource 语法结构,旨在自动管理资源,确保资源在使用后能够及时关闭,避免资源泄露 。

    try (resource declaration) {
      // 使用的资源
    } catch (ExceptionType e1) {
      // 异常块
    }
    
    public class Demo1 {
        public static void main(String[] args) {
            String line;
            try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {//如果多个;隔开继续new
                while ((line = br.readLine()) != null) {
                    System.out.println("Line =>" + line);
                }
            } catch (IOException e) {
                System.out.println("IOException in try block =>" + e.getMessage());
            }
        }
    }
    

    结果:IOException in try block =>test.txt (系统找不到指定的文件。)

    public class Demo1 {
        public static void main(String[] args) {
            BufferedReader br = null;
            String line;
            try {
                System.out.println("Entering try block");
                br = new BufferedReader(new FileReader("test.txt"));
                while ((line = br.readLine()) != null) {
                    System.out.println("Line =>" + line);
                }
            } catch (IOException e) {
                System.out.println("IOException in try block =>" + e.getMessage());
            } finally {//比较繁琐
                System.out.println("Entering finally block");
                try {
                    if (br != null) {
                        br.close();
                    }
                } catch (IOException e) {
                    System.out.println("IOException in finally block =>" + e.getMessage());
                }
            }
        }
    }
    

    全局异常处理器

    在应用程序中,当抛出异常时,如果没有特定的异常处理器来处理该异常,就会尝试使用全局异常处理器来处理

    @RestControllerAdvice
    public class RRExceptionHandler {
    	private Logger logger = LoggerFactory.getLogger(getClass());
    	/**
    	 * 处理自定义异常
    	 */
    	@ExceptionHandler(RRException.class)
    	public R handleRRException(RRException e){
    		R r = new R();
    		r.put("code", e.getCode());
    		r.put("msg", e.getMessage());
    
    		return r;
    	}
    	@ExceptionHandler(NoHandlerFoundException.class)
    	public R handlerNoFoundException(Exception e) {
    		logger.error(e.getMessage(), e);
    		return R.error(404, "路径不存在,请检查路径是否正确");
    	}
    	@ExceptionHandler(DuplicateKeyException.class)
    	public R handleDuplicateKeyException(DuplicateKeyException e){
    		logger.error(e.getMessage(), e);
    		return R.error("数据库中已存在该记录");
    	}
    	@ExceptionHandler(AuthorizationException.class)
    	public R handleAuthorizationException(AuthorizationException e){
    		logger.error(e.getMessage(), e);
    		return R.error("没有权限,请联系管理员授权");
    	}
    	@ExceptionHandler(Exception.class)
    	public R handleException(Exception e){
    		logger.error(e.getMessage(), e);
    		return R.error();
    	}
    }
    

    自定义异常类

    public class RRException extends RuntimeException {
    	private static final long serialVersionUID = 1L;
        private String msg;
        private int code = 500;
       
        public RRException(String msg) {
    		super(msg);
    		this.msg = msg;
    	}
    	public RRException(String msg, Throwable e) {
    		super(msg, e);
    		this.msg = msg;
    	}
    	public RRException(String msg, int code) {
    		super(msg);
    		this.msg = msg;
    		this.code = code;
    	}
    	public RRException(String msg, int code, Throwable e) {
    		super(msg, e);
    		this.msg = msg;
    		this.code = code;
    	}
    	public String getMsg() {
    		return msg;
    	}
    	public void setMsg(String msg) {
    		this.msg = msg;
    	}
    	public int getCode() {
    		return code;
    	}
    	public void setCode(int code) {
    		this.code = code;
    	}
    }
    

    API

    Random

    获取随机数

    public class Demo1 {
        public static void main(String[] args) {
            Random random = new Random(); //new出这个对象
            int randomValue1 = random.nextInt(2);  //调用这个对象的方法 范围是0~1的整数
            System.out.println(randomValue1);
            int randomValue2 = random.nextInt(90) + 10;//范围是10-99的整数
            System.out.println(randomValue2);
            int randomValue3 = random.nextInt(1000) - 500;//范围-500~500,500取不到
            System.out.println(randomValue3);
        }
    }
    

    Scanner

    获取控制台输入的值

    public class Demo1 {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入名称:");
            String name = scanner.nextLine();
            System.out.println("请输入密码:");
            String pwd = scanner.nextLine();
            System.out.println(name + "--左名称右密码--" + pwd);
            System.out.println("请输入整数n:");
            int i = 0;
            if (scanner.hasNextInt()) {                        //加个判断防止异常,还有hasNextDouble等
                i = scanner.nextInt();                         // 判断输入的是否是整数
                System.out.println("整数数据:" + i);
            } else {
                System.out.println("输入的不是整数!");           // 输入错误的信息
            }
            System.out.println("i为" + i);
            scanner.close();                                   //用完就关闭
        }
    }
    
    

    Date

    java.util 包提供了 Date 类来封装当前的日期和时间。 Date 类提供两个构造函数来实例化 Date 对象

    public class Demo1 {
        public static void main(String[] args) {
            Date date = new Date();
            // 参考https://www.runoob.com/java/java-date-time.html
            System.out.printf("全部日期和时间信息:%tc%n", date);
            System.out.printf("年-月-日格式:%tF%n", date);
            System.out.printf("月/日/年格式:%tD%n", date);
            System.out.printf("HH:MM:SS PM格式(12时制):%tr%n", date);
            System.out.printf("HH:MM:SS格式(24时制):%tT%n", date);
            System.out.printf("HH:MM格式(24时制):%tR%n", date);
            System.out.printf("%tY-%tm-%td %tH:%tM:%tS %tZ%n", date, date, date, date, date, date, date);
            System.out.println("-----------------------------------");
            Date dNow = new Date();
            //yyyy 是完整的公元年,MM 是月份,dd 是日期HH:mm:ss 是时、分、秒 SSS毫秒
            SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss:SSS");
            String format = ft.format(dNow);
            System.out.println("当前时间为: " + format);//当前时间为: 2024-06-12 04:59:08:803
        }
    }
    

    Calendar

    Calendar类是一个抽象类,在实际使用时实现特定的子类的对象,创建对象的过程对程序员来说是透明的,只需要使用getInstance方法创建即可

    我们如何才能设置和获取日期数据的特定部分呢,比如说小时,日,或者分钟? 我们又如何在日期的这些部分加上或者减去值呢? 答案是使用Calendar 类

    public class Demo1 {
        public static void main(String[] args) {
            String months[] = {
                    "Jan", "Feb", "Mar", "Apr",
                    "May", "Jun", "Jul", "Aug",
                    "Sep", "Oct", "Nov", "Dec"};
    
            int year;
            // 初始化 Gregorian 日历
            // 使用当前时间和日期
            // 默认为本地时间和时区
            GregorianCalendar gcalendar = new GregorianCalendar();
            // 显示当前时间和日期的信息
            System.out.print("Date: ");
            System.out.print(months[gcalendar.get(Calendar.MONTH)]);
            System.out.print(" " + gcalendar.get(Calendar.DATE) + " ");
            System.out.println(year = gcalendar.get(Calendar.YEAR));
            System.out.print("Time: ");
            System.out.print(gcalendar.get(Calendar.HOUR) + ":");
            System.out.print(gcalendar.get(Calendar.MINUTE) + ":");
            System.out.println(gcalendar.get(Calendar.SECOND));
    
            // 测试当前年份是否为闰年
            if (gcalendar.isLeapYear(year)) {
                System.out.println("当前年份是闰年");
            } else {
                System.out.println("当前年份不是闰年");
            }
        }
    }
    

    Math

    Java 的 Math 包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数

    Math 的方法都被定义为 static 形式,通过 Math 类可以在主函数中直接调用

    public class Test {  
        public static void main (String []args)  
        {  
                System.out.println("返回两个参数中的最大值:" + Math.max(1, 2));
                System.out.println("返回两个参数中的最小值:" + Math.min(0, 3));
                System.out.println("60度的正切值:" + Math.tan(Math.PI / 3));
                System.out.println("1的反正切值: " + Math.atan(1));
                System.out.println("π/2的角度值:" + Math.toDegrees(Math.PI / 2));
                System.out.println(Math.PI);
        }  
    }
    

    String

    String 类是不可改变的final修饰,所以你一旦创建了 String 对象,那它的值就无法改变

    如果需要对字符串做很多修改,那么应该选择使用 StringBuffer & StringBuilder 类

    String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上

    public class Demo1 {
        public static void main(String[] args) {
            String s1 = "Runoob";                       // String 直接创建
            String s2 = "Runoob";                       // String 直接创建
            String s3 = s1;                             // 相同引用
            String s4 = new String("Runoob");    // String 对象创建
            String s5 = new String("Runoob");    // String 对象创建
            System.out.println(s1 == s2);
            System.out.println(s1 == s3);           //s1、s2、s3都是直接创建,都指向同一个公共池里的值和对象
            System.out.println(s1.equals(s3));      //true    值肯定相等、并且都在公共池中
            System.out.println(s4 == s5);           //false   这个比较是对象引用,2个不同对象在不同堆中,值相同
            System.out.println(s4.equals(s5));      //true    这个比较的是值
        }
    }
    

    public class Demo1 {
        public static void main(String[] args) {
            String str = "Hello World";
            System.out.println(str.length());                          //结果11,返回字符串的长度空格和!都算,用于不确定字符串长度时候
            System.out.println(str.charAt(1));                         //e,返回字符串1的位置,从0开始,长度是str的长度-1,可用于验证码的实现
            System.out.println(str.indexOf("h"));                      //-1,查找这个字符,没查到则返回-1
            System.out.println(str.indexOf("o"));                      //4,查找第一个,并返回索引值
            System.out.println(str.substring(4));            //o World,字符串的截取 从下标4开始
            System.out.println(str.substring(4, str.length() - 2));    //o Wor,[4,9)参数1是开始位置 参数2是结束,左闭右开
            System.out.println(str.toLowerCase());                     //全部转小写
            System.out.println(str.toUpperCase());                     //全部转大写
            String[] split = str.split(" ");
            //Hello
            //World
            //根据空格切割
            for (int i = 0; i < split.length; i++) {
                System.out.println(split[i]);
            }
            System.out.println("-----------------------------------");
            String str1 = "Hello1 World2";
            System.out.println(str1.indexOf("1", 4));    //5,查的必须是字符串类型,第二次参数是开始位置,这是正向搜、4,5刚好就是1返回5
            System.out.println(str1.lastIndexOf("l"));            //10,查找最后一个l,并返回它的索引值
            System.out.println(str1.lastIndexOf("l", 11));//10,11是d,然后开始反向搜到l直接返回索引
            System.out.println("-----------------------------------");
            System.out.println("abc".compareTo("abcde"));              //-2,返回整型,比较对应字符的大小(ASCII码顺序)
            System.out.println("abc".compareTo("abc"));                //0,相同返回0
            System.out.println("12789".compareTo("123"));              //4,回字符串长度,比较7和3返回4
            System.out.println("abc".equals("a"));                     //false,判断2个字符串是否相等,需要完全一样
            System.out.println("abc".equals("abc"));                   //True
            System.out.println("abc".equalsIgnoreCase("ABC"));   //true,忽略大小写
            System.out.println("abc".concat("derfg"));                   //abcderfg 字符串拼接,用+也可以
            System.out.println("nnnwa".replace("n", "g"));  //gggwa,替换所有n,第一个参数是需要被替换的,第二个是替换的
            System.out.printf("浮点型变量的值为 " +
                    "%f, 整型变量的值为 " +
                    " %d, 字符串变量的值为 " +
                    "is %s", 1.12f, 16, "LuckyNwa");
            System.out.println("nwa".contains("nw"));                        //true,包含它返回布尔值,顺序有影响
            System.out.println("nwa".endsWith("a"));                         //true,包含它返回布尔值,测试是否以字符a结尾
            System.out.println("  hello world  ".trim());                    //hello world,去除前后空格,不去中间
    
        }
    }
    
    

    https://www.runoob.com/java/java-string.html 参考这

    总结

    length方法使用地方特别多,比如数组遍历时候就需要,字符串同,不知道长度可以直接用这方法获取

    s=“aascsaxaca”;它的下标就是0到s.length()-1

    indexOf可以用来查询是否存在,返回值为-1则不存在,也可以查询这个字符串第一次出现的地方

    charAt方法可用于验证码的实现,把验证码需要的字符串存在一个变量里,通过charAt(new Random().nextInt(codeBox.length()))来获取随机字符

    trim方法去首尾空格,用于登录时候输入有空格的把空格直接去掉,用的范围也挺广 以及split用的很多,可以根据空格,-等分割

    isEmpty判断是否为空

    StringBuffer 和 StringBuilder

    和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象

    StringBuilder 类在 Java 5 中被提出,StringBuilder不是线程安全,StringBuffer 线程安全

    由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类

    public class Demo1 {
        public static void main(String[] args) {
            StringBuilder sb;
            sb = new StringBuilder(10);
            sb.append("Runoob..");
            System.out.println(sb);
            sb.append("!");
            System.out.println(sb);
            sb.insert(8, "Java");
            System.out.println(sb);
            sb.delete(5, 8);
            System.out.println(sb);
            StringBuilder luckyNwa = new StringBuilder("LuckyNwa");
            luckyNwa.append("你好啊");
            System.out.println(luckyNwa);
        }
    }
    

    其他

    转义序列

    前面有反斜杠(\)的字符代表转义字符,它对编译器来说是有特殊含义的

    列表展示了Java的转义序列:

  • 相关阅读:
    Windows 安装docker(详细图解)
    网络信息安全笔记—逻辑漏洞
    双向控制舵机(树莓派版)
    dubbo3.0.5同一个providerAPI的消费组,不同应用的消费者设置不同的消费者参数,会导致其它消费者服务无法启动
    让el-input与其他组件能够显示在同一行
    Codeforces Round #815 (Div. 2)
    在windows中使用mysql workbench连接vmware windows虚拟机中的mysql
    基本知识:block/sleep/hang/宕机/hook/stub/offload/overhead/watermark
    FreeRTOS 任务任务同步与数据传递总结
    dubbo源码解析之服务发布与注册
  • 原文地址:https://blog.csdn.net/weixin_44055864/article/details/139632262