[Java]继承

1. 什么是继承?

继承是面向对象编程的一种机制,允许一个类(叫做子类)继承另一个类(叫做父类)的属性和方法。也就是说,子类可以“继承”父类的行为(方法)和状态(属性),而不需要重新写一遍这些代码。

例子:

假设你有一个父类Animal,它有一个eat方法。你可以创建一个Dog子类,它继承Animal类,这样Dog类就自动拥有Animaleat方法。

// 父类 Animal
class Animal {void eat() {System.out.println("Eating food");}
}// 子类 Dog
class Dog extends Animal {void bark() {System.out.println("Barking");}
}

在上面的例子中,Dog继承了Animal,所以它不仅能使用Dog类自己定义的bark方法,还能使用Animal类的eat方法。也就是说,Dog是“继承”了Animal的。

2. 继承的语法

继承的语法很简单,只需要用extends关键字连接子类和父类。

class Child extends Parent {// 子类的代码
}class 子类 extend 父类{//子类的代码
}
  • Child是子类
  • Parent是父类

3. 构造方法和继承

构造方法是用来初始化对象的,子类不会继承父类的构造方法,但是子类可以通过super()来调用父类的构造方法。super()必须在子类构造方法的第一行。

class Parent {Parent() {System.out.println("Parent constructor");}
}class Child extends Parent {Child() {super();  // 调用父类构造方法System.out.println("Child constructor");}
}

当你创建Child对象时,输出会是:

Parent constructor
Child constructor

因为Child构造方法通过super()先调用了父类的构造方法,然后再执行自己的代码。

4. 重写父类方法

4.1 定义:

子类可以改变父类方法的实现,这叫做“方法重写”(Override)当。子类重写父类的方法时,子类会提供自己版本的实现。

class Animal {void sound() {System.out.println("Some generic sound");}
}class Dog extends Animal {@Override  // 这是注解,表示我们重写了父类的方法void sound() {System.out.println("Bark");}
}

在上面的代码中,Dog类重写了Animal类的sound方法,改成了“Bark”而不是父类的“Some generic sound”。

4.2 重写与重载的区别:

4.2.1 定义

  • 重写(Overriding):指子类重新定义了父类中的方法,以便实现不同的行为。重写发生在继承关系中,子类继承父类的方法,并对其进行修改。子类重写的方法具有与父类方法相同的名称、参数列表和返回类型。

  • 重载(Overloading):指在同一个类中,多个方法具有相同的名字,但参数列表不同。方法的参数列表可以在个数、类型、顺序上有所不同。重载发生在同一个类内,或者子类中也可以重载父类的方法。

4.2.2 发生的场景

  • 重写:发生在子类与父类之间,子类重新定义继承自父类的方法。
  • 重载:发生在同一个类中或继承关系中,方法名相同,但参数不同。

4.2.3 方法签名

  • 重写:重写的方法必须具有与父类被重写方法相同的方法签名,包括方法名称、参数列表、返回类型、异常声明(抛出的异常必须与父类方法抛出的异常相同或更宽松)。重写是动态多态的一部分。

  • 重载:重载的方法具有相同的名称,但参数列表不同。返回类型和异常声明可以不同。重载是静态多态的一部分,编译器在编译时就能确定调用哪个方法。

4.2.4 访问修饰符

  • 重写:子类重写的方法的访问修饰符不能比父类方法更严格。例如,如果父类的方法是public,则子类重写的方法也必须是public,不能是privateprotected

  • 重载:重载方法的访问修饰符可以不同,因为它们属于同一个类或同一个继承层次结构的类。

4.2.5 方法调用时机

  • 重写:方法调用时,Java会根据对象的实际类型来决定调用哪个类的方法,即通过动态绑定(运行时多态)来选择方法。

  • 重载:方法调用时,编译器根据方法的参数列表(数量、类型、顺序)来确定调用哪个版本的方法,即在编译时就能决定。

4.2.6 返回类型

  • 重写:重写方法的返回类型必须与父类方法相同,或者是父类方法返回类型的子类型(协变返回类型)。
    • Java 5 引入了协变返回类型,允许子类方法返回类型是父类方法返回类型的子类。
  • 重载:重载方法可以有不同的返回类型。返回类型并不影响方法的重载判断,重载是通过参数列表的不同来区分的。

4.2.7 例子

重写(Overriding)示例:
class Animal {void sound() {System.out.println("Animal makes a sound");}
}class Dog extends Animal {@Overridevoid sound() {System.out.println("Dog barks");}
}public class Main {public static void main(String[] args) {Animal animal = new Dog();animal.sound();  // 输出:Dog barks}
}
  • 在这个例子中,Dog类重写了Animal类中的sound方法。通过多态,animal引用调用了Dog类的sound方法,表现出不同的行为。
重载(Overloading)示例:
class Printer {void print(String text) {System.out.println(text);}void print(int number) {System.out.println(number);}void print(double number) {System.out.println(number);}
}public class Main {public static void main(String[] args) {Printer printer = new Printer();printer.print("Hello, world!");  // 输出:Hello, world!printer.print(100);  // 输出:100printer.print(99.99);  // 输出:99.99}
}
  • 在这个例子中,Printer类中的print方法被重载了。它有多个版本,分别接收不同类型的参数(Stringintdouble)。编译器根据传入参数的类型来决定调用哪个版本的print方法。

4.2.8 总结:重写与重载的区别

特性重写(Overriding)重载(Overloading)
定义子类重新实现父类的方法,方法签名相同同一类中,多个方法具有相同的方法名,但参数列表不同
发生的场景子类与父类之间同一类中或继承类中
方法签名方法名、参数列表、返回类型相同,抛出的异常应相同或更宽松方法名相同,参数列表不同,返回类型和异常可以不同
访问修饰符子类方法的访问修饰符不能比父类方法更严格访问修饰符可以不同
方法调用时机运行时通过动态

5. super关键字

super关键字是用来在子类中引用父类的。可以用来调用父类的方法、访问父类的构造方法等。

  • 访问父类方法:如果子类重写了父类的方法,可以使用super来调用父类的版本。
    class Animal {void sound() {System.out.println("Some generic sound");}
    }class Dog extends Animal {@Overridevoid sound() {super.sound();  // 调用父类的sound方法System.out.println("Bark");}
    }
    

输出会是:

Some generic sound
Bark
  • 访问父类构造方法:如果子类没有自己的构造方法,默认会调用父类的无参构造方法。如果你想让子类调用父类的带参构造方法,使用super()并传入参数。
    class Parent {Parent(String name) {System.out.println("Parent: " + name);}
    }class Child extends Parent {Child() {super("John");  // 调用父类的构造方法并传入参数System.out.println("Child constructor");}
    }
    

6. final关键字与继承

final关键字用来限制继承的行为。

  • final不能被继承。如果父类是final类,子类不能继承它。

    final class Parent {// 不能被继承
    }class Child extends Parent {  // 错误,不能继承final类
    }
    
  • final方法不能被重写。如果父类的方法是final的,子类不能重写该方法。

    class Parent {final void display() {System.out.println("This is final method");}
    }class Child extends Parent {// 错误,不能重写final方法void display() {System.out.println("Child display");}
    }
    

7. 多继承的限制

Java中不支持类的多继承,意思是一个子类只能有一个父类。如果你尝试让一个类继承多个类,Java会报错。这是为了避免多继承时产生的复杂性和冲突。

不过,Java允许一个类实现多个接口,接口类似于父类,但它只包含方法声明,不包含实现。

8. instanceof关键字

instanceof 是 Java 中非常重要的一个关键字,它用于测试一个对象是否是某个类的实例,或者是该类的子类(或实现的接口)的实例。它常常用于进行类型检查,确保对象的类型与预期匹配,从而避免类型转换时出现ClassCastException异常。

8.1 instanceof的基本语法

object instanceof ClassName
  • object:你要检查的对象。
  • ClassName:你要检查的类或接口的名称。

instanceof返回一个布尔值,如果对象是指定类或接口的实例,返回true,否则返回false

8.2 使用instanceof的场景

instanceof常用于以下场景:

  • 类型检查:确保对象是某个类或接口的实例。
  • 避免ClassCastException:在进行类型转换之前,先使用instanceof检查对象的类型,避免类型转换错误。
  • 多态的实现:在实现多态时,可能需要根据对象的实际类型来执行不同的代码。

8.3  例子解析

示例 1:检查对象是否是某个类的实例
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}public class Main {public static void main(String[] args) {Animal a = new Dog();  // a 是 Dog 类的实例if (a instanceof Dog) {//检验对象a是否为Dog类的实例System.out.println("a is an instance of Dog");}if (a instanceof Animal) {//检验对象a是否为Animal类的实例System.out.println("a is an instance of Animal");}if (a instanceof Cat) {//检验对象a是否为Cat类的实例System.out.println("a is an instance of Cat");}}
}

输出:

a is an instance of Dog
a is an instance of Animal
  • 这里,aDog的实例,所以a instanceof Dog返回true,并输出a is an instance of Dog
  • a也是Animal的实例,因为Dog继承自Animal,所以a instanceof Animal也返回true,并输出a is an instance of Animal
  • a不是Cat的实例,所以a instanceof Cat返回false,没有输出。
示例 2:避免ClassCastException
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}public class Main {public static void main(String[] args) {Animal a = new Dog();  // a 是 Dog 类的实例// 在进行类型转换之前,使用 instanceof 检查类型if (a instanceof Dog) {Dog dog = (Dog) a;  // 安全转换,因为 a 确实是 Dog 类的实例System.out.println("Successfully cast to Dog");}// 错误的类型转换if (a instanceof Cat) {Cat cat = (Cat) a;  // 运行时会抛出 ClassCastException,因为 a 不是 Cat 类的实例System.out.println("Successfully cast to Cat");}}
}
  • a instanceof Dogtrue,所以可以安全地将a转换为Dog类型。
  • a instanceof Catfalse,因此不会进行转换,避免了ClassCastException异常。
示例 3:instanceof与接口

instanceof不仅可以用于类,还可以用于接口的实例检查。

interface Playable {void play();
}class Dog implements Playable {@Overridepublic void play() {System.out.println("Dog is playing");}
}public class Main {public static void main(String[] args) {Playable p = new Dog();if (p instanceof Playable) {//检验对象p是否为Playable的实例System.out.println("p is an instance of Playable");}if (p instanceof Dog) {//检验对象p是否为Dog的实例System.out.println("p is an instance of Dog");}}
}

输出:

p is an instance of Playable
p is an instance of Dog
  • p instanceof Playable返回true,因为Dog实现了Playable接口。
  • p instanceof Dog返回true,因为p实际上是Dog类的实例。

8.4 instanceofnull的情况

instanceof在对象为null时,始终返回false,不会抛出NullPointerException

class Animal {}
class Dog extends Animal {}public class Main {public static void main(String[] args) {Animal a = null;if (a instanceof Dog) {System.out.println("a is an instance of Dog");} else {System.out.println("a is not an instance of Dog");}}
}

输出:

a is not an instance of Dog

即使a的类型是Animal(它是Dog类的父类),但由于anullinstanceof检查返回false,不会抛出异常。

8.5  instanceof的性能影响

instanceof运算符的性能是相对较高效的,因为它只会检查对象的运行时类型。然而,如果频繁调用instanceof,或者在大规模的数据结构中进行类型检查,可能会对性能产生一定影响。在这种情况下,考虑优化设计,尽量避免过多的类型检查。

8.6  instanceof的应用场景

  • 类型安全:使用instanceof可以确保类型转换是安全的,避免运行时错误。
  • 多态性实现:通过instanceof判断不同对象的类型,决定调用不同的代码实现。这常见于策略模式、访问者模式等设计模式。
  • 类型检查:在处理复杂的对象层次结构时,使用instanceof可以检测对象的实际类型,并根据不同类型做出不同的处理。

8.7 总结

  • instanceof是用于检查一个对象是否是某个类或接口的实例。
  • 它可以确保在进行类型转换时避免ClassCastException异常。
  • instanceof不仅能检查类的实例,还能检查对象是否实现了某个接口。
  • null对象上使用instanceof时,始终返回false
  • 使用instanceof时要注意性能问题,但它通常是类型检查的最直接和最安全的方式。

9. 子类和父类之间的关系

子类继承了父类的所有字段和方法,意味着子类可以直接使用父类的这些属性和行为。但是,子类并不继承父类的构造方法、初始化块等。

  • 继承的深度:继承不仅是直接的父类和子类关系,Java支持多层继承。也就是说,子类继承父类,父类继承祖父类,依此类推。
    class Grandparent {void greet() {System.out.println("Hello from Grandparent");}
    }class Parent extends Grandparent {void greet() {System.out.println("Hello from Parent");}
    }class Child extends Parent {void greet() {System.out.println("Hello from Child");}
    }
    

当你创建Child对象并调用greet方法时,它会首先执行子类的实现。如果你希望调用父类或祖父类的实现,可以使用super

Child c = new Child();
c.greet();  // 输出:Hello from Child

10. 访问控制符与继承

Java的访问控制符(public, protected, private, 默认(package-private))决定了类、方法或变量的可见性和访问权限。继承时,访问控制符对子类的访问有影响。

  • public:可以被任何类访问。
  • protected:可以被同一包中的类访问,也可以被子类访问(即使子类在不同包中)。
  • private:只能在同一类中访问,不能被子类直接访问。
  • 默认(package-private)只能在同一包中访问,不能被子类访问(即使在同一包外的子类)。
例子:
class Parent {public void publicMethod() {System.out.println("public method");}protected void protectedMethod() {System.out.println("protected method");}private void privateMethod() {System.out.println("private method");}void defaultMethod() {System.out.println("default method");}
}class Child extends Parent {void testMethods() {publicMethod();    // 子类可以访问protectedMethod(); // 子类可以访问// privateMethod(); // 错误:无法访问父类的private方法defaultMethod();   // 子类可以访问默认方法(同一包)}
}

11. 接口与继承

虽然Java不支持多继承(即一个类不能继承多个类),但一个类可以实现多个接口。这是Java实现多重继承的一种方式。

  • 接口:接口定义了一些方法的签名,但没有方法的实现。类可以实现接口,并提供这些方法的具体实现。
    interface Animal {void eat();
    }interface Mammal {void giveBirth();
    }class Dog implements Animal, Mammal {@Overridepublic void eat() {System.out.println("Dog is eating");}@Overridepublic void giveBirth() {System.out.println("Dog gives birth to puppies");}
    }
    

在这个例子中,Dog类实现了AnimalMammal两个接口,因此必须实现这两个接口中的方法。

12. 多态与继承

多态是指同一个方法调用在不同的对象上表现出不同的行为。多态依赖于继承和方法重写。

  • 方法重写(Override)是多态的基础,允许子类实现父类方法的不同版本。
    class Animal {//由Animal这个类延伸得到Dog类和Cat类,这个由一个类得到多个功能不同的类的过程叫多态void sound() {System.out.println("Animal makes a sound");}
    }class Dog extends Animal {@Overridevoid sound() {//由Animal类中的sound方法重写得到Dog类中的另外一个方法,这个过程叫方法重写System.out.println("Dog barks");}
    }class Cat extends Animal {@Overridevoid sound() {//由Animal类中的sound方法重写得到Cat类中的另外一个方法,这个过程叫方法重写System.out.println("Cat meows");}
    }public class Polymorphism_And_Overriding{public static void main(String[] args){Animal a1 = new Dog();a1.sound();  // 输出:Dog barksAnimal a2 = new Cat();a2.sound();  // 输出:Cat meows}
    }
    

通过多态,可以在运行时动态选择调用哪个类的方法。

13. 抽象类与继承

抽象类是不能实例化的类,它通常用作其他类的基类。抽象类可以有抽象方法(没有方法体),也可以有非抽象方法。

  • 抽象方法:在抽象类中定义的方法,只声明没有实现,子类必须提供具体实现。
  • 非抽象方法:普通方法,可以在抽象类中定义实现,子类可以继承或者重写。
    abstract class Animal {abstract void sound();  // 抽象方法,没有实现void sleep() {System.out.println("Animal is sleeping");  // 普通方法,已实现}
    }class Dog extends Animal {@Overridevoid sound() {System.out.println("Dog barks");//实现抽象类中的抽象方法}
    }
    

14. 继承的设计原则

在使用继承时,遵循一些设计原则非常重要:

  • “是一个”关系:子类应该是父类的一种“特化”。即,子类应该能够代替父类使用。例如,Dog类继承自Animal类,因为“狗是一种动物”。
  • 优先使用组合而非继承:有时使用组合比继承更能让代码灵活。例如,可以让一个类拥有另一个类的实例,而不是继承它。继承使得子类与父类耦合太紧密,而组合允许更松散的关联。

15.总结

继承是面向对象编程的核心概念之一,它允许我们从已有的类中“继承”字段和方法,进而提高代码的复用性。在继承中,我们可以利用super来访问父类成员,使用@Override来重写父类方法,并通过多态来实现动态方法调用。

继承的好处在于它可以帮助我们减少重复代码,但也要小心使用,避免过度依赖继承,特别是要理解父类与子类之间的关系,并遵循设计原则。如果能在适当的时候使用组合,能够获得更加灵活的代码结构。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/68707.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

双指针c++

双指针(Two Pointers)是一种常用的算法技巧,通常用于解决数组或链表中的问题,如滑动窗口、区间合并、有序数组的两数之和等。双指针的核心思想是通过两个指针的移动来优化时间复杂度,通常可以将 (O(n^2)) 的暴力解法优…

第05章 16 Implicit Function应用举例

Implicit Function在VTK中有多种广泛的应用场合,以下是一些主要的应用场景及其详细说明: 1. 几何裁剪(Clipping) Implicit Function可以用于对几何体进行裁剪,生成新的几何形状。裁剪操作通常基于一个Implicit Funct…

【二叉搜索树】

二叉搜索树 一、认识二叉搜索树二、二叉搜索树实现2.1插入2.2查找2.3删除 总结 一、认识二叉搜索树 二叉搜索树(Binary Search Tree,简称 BST)是一种特殊的二叉树,它具有以下特征: 若它的左子树不为空,则…

洛谷P3372 【模板】线段树 1以及分块

【模板】线段树 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 将某区间每一个数加上 k k k。求出某区间每一个数的和。 输入格式 第一行包含两个整数 n , m n, m n,m,分别表示该数列数字的个数和操作的总个数。 …

Linux运维之Linux的安装和配置

目录 Linux的基本概念: 1.为什么要使用Linux? 2.什么是Linux? Linux的安装和配置: 1.下载Linux的虚拟机和镜像文件: 1.1下载虚拟机 1.2下载镜像文件 2.在虚拟机或者物理机中安装Linux操作系统 3.配置虚拟机的…

Google 和 Meta 携手 FHE 应对隐私挑战

1. 引言 为什么世界上最大的广告商,如谷歌和 Meta 这样的超大规模公司都选择全同态加密 (FHE)。 2. 定向广告 谷歌和 Meta 是搜索引擎和社交网络领域的两大巨头,它们本质上从事的是同一业务——广告。它们最近公布的年度广告收入数据显示,…

【ArcMap零基础训练营】01 ArcMap使用入门及绘图基础

ArcMap入门及使用技巧 230106直播录像 ArcMap使用技巧及制图入门 ArcGIS的安装 本次教学使用的ArcMap版本为10.7,建议各位安装ArcGIS10.0及其以上版本的英文版本。 下载及安装详细教程可参考ArcGIS 10.8 for Desktop 完整安装教程 麻辣GIS 改善使用体验的几个操作…

一个 windows 自动语音识别案列

一个 windows 自动语音识别案列 之前给写过一段很有意思的代码,今天分享给大家 ! 文章目录 一个 windows 自动语音识别案列前言一、需要安装一些python 库二、代码如下三,测试总结下前言 一、需要安装一些python 库 speech_recognition:这是一个用于语音识别的库。它可以…

程序员学英文之At the Airport Customs

Dialogue-1 Making Airline Reservation预定机票 My cousin works for Xiamen Airlines. 我表哥在厦航上班。I’d like to book an air ticket. 我想预定一张机票。Don’t judge a book by its cover. 不要以貌取人。I’d like to book / re-serve a table for 10. 我想预定一…

[250125] DeepSeek 发布开源大模型 R1,性能比肩 OpenAI o1 | 希捷推出高达 36TB 的硬盘

DeepSeek 发布开源大模型 R1,性能比肩 OpenAI o1 DeepSeek 正式发布了 DeepSeek-R1 大模型,并同步开源了模型权重,其性能对标 OpenAI o1 正式版。 🌟 主要亮点: 开源模型,MIT 许可证: DeepSe…

Python 写的几个经典游戏 新年放烟花、 贪吃蛇、俄罗斯方块、超级玛丽、五子棋、蜘蛛纸牌

0、新年放烟花 import pygame import random import math# 初始化Pygame pygame.init()# 设置窗口 WIDTH 800 HEIGHT 600 screen pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("新年放烟花")# 颜色定义 BLACK (0, 0, 0) WHITE (255, 2…

Python Typing: 实战应用指南

文章目录 1. 什么是 Python Typing?2. 实战案例:构建一个用户管理系统2.1 项目描述2.2 代码实现 3. 类型检查工具:MyPy4. 常见的 typing 用法5. 总结 在 Python 中,静态类型检查越来越受到开发者的重视。typing 模块提供了一种方式…

canvas的基本用法

canvas canvas元素简介 1.是个container元素<canvas width100 height100></canvas>&#xff0c;有开闭标签 2.有且只有width和height两个attribute&#xff0c;不需要写单位 canvas的基本使用 const canvasEl document.getElementById(canvas01) const ctx …

【自学笔记】计算机网络的重点知识点-持续更新

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 计算机网络重点知识点一、计算机网络概述二、网络分类三、网络性能指标四、网络协议与体系结构五、数据交换方式六、物理层与数据链路层七、网络层与运输层八、应用…

14-8C++STL的queue容器

一、queue容器 (1)queue容器的简介 queue为队列容器&#xff0c;“先进先出”的容器 (2)queue对象的构造 queue<T>q; queue<int>que Int;//存放一个int的queue容器 queue<string>queString;//存放一个string的queue容器 (3)queue容器的push()与pop()方…

计算机毕业设计Python+CNN卷积神经网络高考推荐系统 高考分数线预测 高考爬虫 协同过滤推荐算法 Vue.js Django Hadoop 大数据毕设

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

PyCharm接入DeepSeek实现AI编程

目录 效果演示 创建API key 在PyCharm中下载CodeGPT插件 配置Continue DeepSeek 是一家专注于人工智能技术研发的公司&#xff0c;致力于开发高性能、低成本的 AI 模型。DeepSeek-V3 是 DeepSeek 公司推出的最新一代 AI 模型。其前身是 DeepSeek-V2.5&#xff0c;经过持续的…

C语言指针专题一 -- 指针基础原理

目录 1. 指针概念 地址和变量 指针 2. 指针的声明与初始化 3. 指针的使用 指针访问 指针的运算 指针与数组 指针与函数 4. 编程实例 5. 指针的常见陷阱与防御 6. 总结 1. 指针概念 地址和变量 在C语言中&#xff0c;地址和变量是两个基本但非常重要的概念。 1. 变…

动手学图神经网络(4):利用图神经网络进行图分类

利用图神经网络进行图分类:从理论到实践 引言 在之前的学习中,大家了解了如何使用图神经网络(GNNs)进行节点分类。本次教程将深入探讨如何运用 GNNs 解决图分类问题。图分类是指在给定一个图数据集的情况下,根据图的一些结构属性对整个图进行分类,而不是对图中的节点进…

【Python】已解决:ModuleNotFoundError: No module named ‘cv2’

个人简介&#xff1a;某不知名博主&#xff0c;致力于全栈领域的优质博客分享 | 用最优质的内容带来最舒适的阅读体验&#xff01;文末获取免费IT学习资料&#xff01; &#x1f345; 文末获取更多信息 &#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅收藏 &#x…