• Java面向对象(基础)-- 类的成员之三:构造器(Constructor)



    类的成员之三: 构造器(constructor),又叫 构造方法(和一般的方法不一样)

    类的成员,前面还有属性和方法,还没有来得及更,先往后走,有空我再更。学到这里的应该都知道吧~

    一、介绍

    (1)理解和作用

    【构造器的理解】

    我们new完对象时,所有成员变量都是默认值,如果我们需要赋别的值,需要挨个为它们再赋值,太麻烦了。

    我们能不能在new对象时,直接为当前对象的某个或所有成员变量直接赋值呢? 可以,Java给我们提供了 构造器(Constructor) ,也称为 构造方法

    构造器非常常用,一个类里面一定会有构造器

    即使是抽象类(这个类不能造对象),也有构造器。

    constructor :n. 建设者、建造者

    construct:v. 建设、建造、创造

    construction: n. 建设、建造 CCB

    【构造器的作用】

    作用1:搭配new关键字,创建类的对象

    作用2:在创建对象的同时,可以给对象的相关属性赋值

    new对象,并在new对象的时候为实例变量赋值。

    举例:Person p = new Person(“Peter”,15) ;

    解释:如同我们规定每个“人”一出生就必须先洗澡,我们就可以在“人”的构造器中加入完成“洗澡”的程序 代码,于是每个“人”一出生就会自动完成“洗澡”,程序就不必再在每个人刚出生时一个一个地告诉他们 要“洗澡”了。

    (2) 构造器的语法格式

    [修饰符] class 类名{
        [修饰符] 构造器名(){
        	// 实例初始化代码
        }
        [修饰符] 构造器名(参数列表){
        	// 实例初始化代码
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    说明:

    1. 构造器名必须与它所在的类名必须相同
    2. 它没有返回值,所以不需要返回值类型,也不需要void
    3. 构造器的修饰符只能是权限修饰符,不能被其他任何修饰。比如,不能被static、final、 synchronized、abstract、native修饰,不能有return语句返回值。

    【举例】
    image.png

    之前用过的Scanner:

    Scanner scan =new Scanner(System.in);
    
    • 1

    Scanner()就是一个构造器,构造器里面有形参,这里传入了一个实参System.in。

    二、举例剖析

    💀举例

    (1)构造器在哪

    比如现在创建一个类【Person.java】:

    package yuyi.exer02;
    
    /**
     * ClassName: Person
     * Package: yuyi.exer02
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/10/23 0023 8:43
     */
    public class Person {
        //属性(先不考虑权限的问题)
        String name;
        int age;
    
        //方法
        public void eat(){
            System.out.println("人吃饭");
        }
        public void sleep(int hour){
            System.out.println("每天睡眠"+hour+"小时");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    再创建一个测试类【PersonTest.java】:

    package yuyi.exer02;
    
    public class PersonTest {
        public static void main(String[] args) {
            //创建类的对象
            Person p1=new Person(); //类型 变量名 =new 具体对象
    
            //通过对象来调属性、调方法
            p1.eat();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其实Person()就是构造器:
    image.png

    点击这个位置,创建新的字节码文件:(反编译)
    image.png

    在out文件夹下,找到相应目录,可以看到被隐藏的构造器:(记得点左上角刷新一下)
    image.png


    (2)权限问题

    若将Person类的修饰符Public去掉:
    image.png

    再看一下字节码文件:
    image.png

    可以看到,默认生成的构造器的权限与类声明的权限一致。

    (3)声明构造器

    构造器声明的格式:权限修饰符 类名(形参列表){}

    ①隐藏的构造器

    上面可以看到,隐藏的构造器是这样的:

    //构造器
    public Person(){
    
    }
    
    • 1
    • 2
    • 3
    • 4

    如图:
    image.png

    若在Person构造器里面加上输出语句:

    //构造器
    public Person(){
    	System.out.println("我是构造器");
    }
    
    • 1
    • 2
    • 3
    • 4

    可以在测试类里面运行出来:
    image.png


    ②显示的构造器

    我们可以显示的声明其他构造器。

    package yuyi.exer02;
    
    public class Person {
        //属性(先不考虑权限的问题)
        String name;
        int age;
    
        //默认构造器
        /*public Person(){
            System.out.println("我是构造器");
        }*/
    
        //声明其他构造器
        public Person(int a){    //参数一般考虑对类中属性赋值
            age=a;  //通过这个构造器,造对象的同时把属性age赋值
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    同样可以在测试类里面创造对象,但此时会看到一个报错:
    image.png

    报错内容:
    image.png

    一旦类中显示声明了构造器,则系统不再提供默认的空参的构造器。

    若此时还想用这个空参的构造器,需要自行定义:
    image.png


    显示构造之后,可以在测试类里面赋值并输出:

    public class PersonTest {
        public static void main(String[] args) {
            //创建类的对象
            Person p2=new Person(1);
            System.out.println(p2.age);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出结果:
    image.png

    (4)声明多个构造器

    在一个类中可以声明多个构造器,比如再声明一个,对name属性进行初始化:

    public Person(String n){
            name=n;
    }
    
    • 1
    • 2
    • 3

    或者对name属性和age属性同时给初始化:

    public Person(String n,int a){
            name=n;
            age=a;
    }
    
    • 1
    • 2
    • 3
    • 4

    这些构造器构成重载。

    再比如String:(API)
    image.png

    (5)构造器重点总结说明

    构造器声明的格式:权限修饰符 类名(形参列表){}

    4种权限都能用来修饰构造器。

    没有返回值类型,直接写构造器的名字。

    小括号里面是形参列表。

    大括号里面是构造器体。

    创建类以后,在没有显示提供任何构造器的情况下,系统会默认提供一个空参的构造器,且构造器的权限类声明的权限相同。

    一旦类中显示声明了构造器,则系统不再提供默认的空参的构造器。

    一个类中可以声明多个构造器,彼此之间构成重载。

    三、练习

    (1)练习1

    🌋题目描述

    (1)定义Student类,有4个属性:

    String name;

    int age;

    String school;

    String major;

    (2)定义Student类的3个构造器:

    • 第一个构造器Student(String n, int a)设置类的name和age属性;
    • 第二个构造器Student(String n, int a, String s)设置类的name, age 和school属性;
    • 第三个构造器Student(String n, int a, String s, String m)设置类的name, age ,school和major属性;

    (3)在main方法中分别调用不同的构造器创建的对象,并输出其属性值。

    🤺代码

    package anli;
    
    public class Student {
        //属性
        String name;
        int age;
        String school;
        String major;
    
        //构造器
        public Student(String n, int a){
            name=n;
            age=a;
        }
        public Student(String n, int a, String s){
            name=n;
            age=a;
            school=s;
        }
        public Student(String n, int a, String s, String m){
            name=n;
            age=a;
            school=s;
            major=m;
        }
    }
    
    class StudentTest{
        public static void main(String[] args) {
            Student one=new Student("张三",19);
            Student two=new Student("李四",20,"哈佛");
            Student three=new Student("王强",22,"北大","硕士");
            System.out.println("name="+one.name+",age="+one.age);
            System.out.println("name="+two.name+",age="+two.age+",school="+two.school);
            System.out.println("name="+three.name+",age="+three.age+",school="+three.school+",major="+three.major);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    ⚡输出结果
    image.png

    👻注意

    ①构造器没有初始化的属性,默认值是null:(String类型举例)
    image.png

    ②小技巧

    在调用构造器的时候,因为有很多重载,所以参数不同,可以点击小括号,将光标放在小括号内,按Ctrl+P就可以显示各个参数:
    image.png

    ③可以在Student方法内定义一个方法,方便输出。

    public class Student{
        //...
        public String getInfo(){
            return "name= "+name+",age= "+age+",school= "+school+",major= "+major;
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在测试类里面调用:

    class StudentTest{
        public static void main(String[] args) {
            Student four=new Student("黎明",45,"海淀大学","医科");
            System.out.println(four.getInfo());
            //构造器的作用:搭配new创建对象、通过参数的方式给创建的对象的相关属性赋值
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出结果:
    image.png

    (2)练习2

    🌋题目描述

    编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底边长base和高height,

    同时声明公共方法访问私有变量。此外,提供类必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。

    angle:角

    angel:天使

    🤺代码

    【TriAngle.java】

    package anli;
    
    /**
     * ClassName: TriAngle
     * Package: anli
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/10/23 0023 11:16
     */
    public class TriAngle {
        //①属性
        private double base;   //底边长
        private double height; //高
    
    
        //②方法
        //1.1设置底边长
        public void setBase(double a){
            base=a;
        }
        //1.2获得底边长
        public double getBase(){
            return base;
        }
    
        //2.1设置高
        public void setHeight(double b){
            height=b;
        }
        //2.2获得高
        public double getHeight(){
            return height;
        }
    
        //求面积的方法
        public double findArea(){   //不需要形参,调用方法直接使用底边长和高即可
            return base * height /2;
        }
    
    
        //③构造器
        //习惯上给一个类提供构造器的时候,会先写一个空参构造器
        public TriAngle(){
    
        }
        public TriAngle(double b,double h ){
            base=b;
            height=h;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    【TriAngleTest.java】

    package anli;
    
    /**
     * ClassName: TriAngleTest
     * Package: anli
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/10/23 0023 11:17
     */
    public class TriAngleTest {
        public static void main(String[] args) {
            //创建TriAngle实例1
            TriAngle t1=new TriAngle();
            //属性被私有化了,要通过调用方法来设置属性
            t1.setBase(3.4);
            t1.setHeight(2.3);
            System.out.println("面积为:"+t1.findArea());
    
            //创建TriAngle实例2
            TriAngle t2=new TriAngle(2.4,4.5);  //通过构造器给属性赋值
            //输出看一下是否真的赋值了
            System.out.println("底边长为:"+t2.getBase());
            System.out.println("高为:"+t2.getHeight());
            System.out.println("面积为:"+t2.findArea());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    记得看注释哦~

    get、set不会写的看一下这一篇:https://blog.csdn.net/m0_55746113/article/details/133980641?spm=1001.2014.3001.5501

    ⚡输出结果
    image.png

    (3)练习3

    🌋题目描述

    1、写一个名为Account的类模拟账户。该类的属性和方法如下图所示。

    该类包括的属性:账号id,余额balance,年利率annualInterestRate;

    包含的构造器:自定义

    包含的方法:访问器方法(getter和setter方法),取款方法withdraw(),存款方法deposit()。

    提示:在提款方法withdraw中,需要判断用户余额是否能够满足提款数额的要求,如果不能,应给出提示。

    image.png

    2、创建Customer类。

    a. 声明三个私有对象属性:firstName、lastName和account。

    b. 声明一个公有构造器,这个构造器带有两个代表对象属性的参数(f和l)

    c. 声明两个公有存取器来访问该对象属性,方法getFirstName和getLastName返回相应的属性。

    d. 声明setAccount 方法来对account属性赋值。

    e. 声明getAccount 方法以获取account属性。

    image.png

    3、写一个测试程序。

    (1)创建一个Customer ,名字叫 Jane Smith, 他有一个账号为1000,余额为2000元,年利率为 1.23% 的账户。

    (2)对Jane Smith操作。

    存入 100 元,再取出960元。再取出2000元。

    打印出Jane Smith 的基本信息:

    成功存入 :100.0

    成功取出:960.0

    余额不足,取款失败

    Customer [Smith, Jane] has a account: id is 1000, annualInterestRate is 1.23%, balance is 1140.0

    🤺代码

    【Account.java】

    package anli;
    
    /**
     * ClassName: Account
     * Package: anli
     * Description:
     * 该类包括的属性:账号id,余额balance,年利率annualInterestRate;
     * 包含的构造器:自定义
     * 包含的方法:访问器方法(getter和setter方法),取款方法withdraw(),存款方法deposit()。
     *
     * 提示:在提款方法withdraw中,需要判断用户余额是否能够满足提款数额的要求,如果不能,应给出提示。
     * @Author 雨翼轻尘
     * @Create 2023/10/23 0023 11:59
     */
    public class Account {
        //属性
        private int id; //账号
        private double balance; //余额
        private double annualInterestRate;  //年利率
    
        //构造器
        public Account(){
    
        }
        public Account(int i,double b,double a){
            id=i;
            balance=b;
            annualInterestRate=a;
        }
    
        //方法
        //1.1设置账号
        public void setId(int i){
            id=i;
        }
        //1.2获得账号
        public int getId(){
            return id;
        }
    
        //2.1设置余额
        public void setBalance(double b){
            balance=b;
        }
        //2.2获得余额
        public double getBalance(){
            return balance;
        }
    
        //3.1设置年利率
        public void setAnnualInterestRate(double a){
            annualInterestRate=a;
        }
        //3.2获得年利率
        public double getAnnualInterestRate(){
            return annualInterestRate;
        }
    
        //取钱
        public void withdraw(double amount){
            if(amount<=balance && amount> 0){    //说明余额够
                balance-=amount;
                System.out.println("成功取出:"+amount);
            }else{
                System.out.println("余额不足,取款失败~");
            }
        }
        //存钱
        public void deposit(double amount){
            if(amount>=0){  //充入的钱是正数
                balance+=amount;
                System.out.println("成功存入: "+amount);
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    【Customer.java】

    package anli;
    
    /**
     * ClassName: Customer
     * Package: anli
     * Description:
     * a. 声明三个私有对象属性:firstName、lastName和account。
     * b. 声明一个公有构造器,这个构造器带有两个代表对象属性的参数(f和l)
     * c. 声明两个公有存取器来访问该对象属性,方法getFirstName和getLastName返回相应的属性。
     * d. 声明setAccount 方法来对account属性赋值。
     * e. 声明getAccount 方法以获取account属性。
     * @Author 雨翼轻尘
     * @Create 2023/10/23 0023 12:37
     */
    public class Customer {
        //属性
        private String firstName;
        private String lastName;
        private Account account;    //account是自定义类属性
        //在一个类(Customer)里面可以声明另外一个类(Account)的成员变量,
        // 另外这个类可以是系统提供现成的(比如String),也可以是自定义类(Account)
    
    
        //构造器
        //在创建对象的时候,并没有给account赋值,此时account是NULL,可以在下面的方法中对account属性赋值
        public Customer(String f,String l){
            firstName=f;
            lastName=l;
        }
    
        //方法
        //1.针对姓名只有get方法(相当于给名字属性私有化之后,并没有提供set方法,就是一旦设置好之后就不允许再改变了)
        public String getFirstName(){
            return firstName;
        }
        public String getLastName(){
            return lastName;
        }
    
        //2.针对account提供get和set方法
        public void setAccount(Account a){
            account=a;
        }
        public Account getAccount(){
            return account;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    【CustomerTest.java】

    package yuyi.exer01.exe01.test2;
    
    import anli.Account;
    import anli.Customer;
    
    /**
     * ClassName: CustomerTest
     * Package: yuyi.exer01.exe01.test2
     * Description:
     *(1)创建一个Customer ,名字叫 Jane Smith, 他有一个账号为1000,余额为2000元,年利率为 1.23% 的账户。
     *(2)对Jane Smith操作。
     * 存入 100 元,再取出960元。再取出2000元。
     * 打印出Jane Smith 的基本信息:
     *
     * 成功存入 :100.0
     * 成功取出:960.0
     * 余额不足,取款失败
     * Customer [Smith, Jane] has a account: id is 1000, annualInterestRate is 1.23%, balance is 1140.0
     *
     * @Author 雨翼轻尘
     * @Create 2023/10/23 0023 16:24
     */
    public class CustomerTest {
        public static void main(String[] args) {
            //1.创建Customer实例
            Customer customer=new Customer("Jane","Smith"); //通过构造器对类中的属性赋值
    
            //2.创建账户
            Account account=new Account(1000,2000,0.0123);
    
            //3.客户与账户建立联系
            customer.setAccount(account);
    
    
            //4.针对于客户的账户进行取钱、存钱的操作
            //方法一
            /*不要直接通过account进行操作,就好像银行在操作一样,现在要体现自己操作
            account.deposit(100);//存钱
            account.withdraw(960);//取钱
            account.withdraw(2000);//取钱*/
    
            //方法二
            //先通过客户找到账户,拿着账户再去存钱
            customer.getAccount().deposit(100); //存钱100
            customer.getAccount().withdraw(960);    //取钱960
            customer.getAccount().withdraw(2000);   //取钱2000
    
            //5.输出客户信息
            System.out.println("Customer ["+customer.getLastName()+", "+customer.getFirstName()+"] has a account: " +
                    "id is "+customer.getAccount().getId()+
                    ", annualInterestRate is "+ customer.getAccount().getAnnualInterestRate()*100+
                    "%, balance is "+ customer.getAccount().getBalance());
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    ⚡输出结果
    image.png

    👻注意

    ①重要代码分析
    Customer.png

    ②补充知识点

    	//1.创建Customer实例
    	Customer customer=new Customer("Jane","Smith"); //通过构造器对类中的属性赋值
    
        //2.创建账户
        Account account=new Account(1000,2000,0.0123);	//创建了一个账户,账户的名字叫account
    
        //3.客户与账户建立联系
        customer.setAccount(account);	//账户的名字account(变量)赋值给customer的setAccount属性
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    上面代码的第2个和第3个可以合并起来:

    customer.setAccount(new Account(1000,2000,0.0123));	
    //在堆空间创造了一个对象new Account(1000,2000,0.0123),这个对象没有名字,叫做匿名对象
    
    • 1
    • 2

    匿名对象:创建的对象没有名字。


    【举例】

    在main方法里面,取1000块钱:

    //关于匿名对象
    new Account(1001,2000,0.0123).withdraw(1000);   //取钱
    
    • 1
    • 2

    输出结果:
    image.png

    若想看一下刚才创建的对象它的账户余额,这样调用是不可行的:

    System.out.println(new Account(1001, 2000, 0.0123).getBalance());//不可行,这里又会创建一个新的对象
    
    • 1

    输出结果:
    image.png

    上面造的匿名对象Account…,下面输出的时候还想拿到那个对象,是不行的

    匿名对象只能用一次,后边就找不到了。

    在java里面调用一个对象或一个值,都是通过变量名来调用的。

    之前我们都是将对象赋值给一个具体的对象,比如:

    Account account=new Account(1000,2000,0.0123);
    
    • 1

    若想拿到这个对象,直接拿变量名account来操作就可以了。

    匿名的话就只能调用一次啦。


    那匿名对象咋用嘞?

    开发当中,通常就是这样使用:
    image.png

    当造好的对象被赋值给了一个变量,紧接着又调用了这个变量,这个变量后边也没有用,就可以这样使用。

    1.匿名对象往往只能被调用一次。

    2.通常匿名对象作为实参传递给方法的形参。


    小Tips:

    customer.setAccount(new Account(1000,2000,0.0123));	
    
    • 1

    其实,在setAccount方法里面,针对a是可以多次调用的:
    image.png

    所谓的匿名对象传进setAccount内之后就有名了,在setAccount方法里面可以多次调用。


    【注】纯手敲难免有误,欢迎各位读者指正,感兴趣的欢迎关注专栏:http://t.csdnimg.cn/XEkfM,后续会持续更新,关注博主不迷路~

  • 相关阅读:
    Java核心知识体系3:异常机制详解
    NETA“一鸣惊人”,7月交付超过蔚来,Xpeng和LiAuto,国产之光?
    免实名域名是什么意思?
    通过实战总结的 使用GoFrame小技巧
    Elasticsearch:自定义应用程序的日志记录 - Elastic Common Schema
    Python光速入门 - Flask轻量级框架
    MySQL---MGR保姆版
    15天深度复习JavaWeb的详细笔记(六)——HTTP、Tomcat、Servlet
    现代 ERP 系统,如何使中小企业智能制造商受益?
    WSL+VSCODE安装以及使用
  • 原文地址:https://blog.csdn.net/m0_55746113/article/details/134002260