浅谈Spring

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

一、什么是IOC?

IoC = Inversion of Control 翻译成中⽂是“控制反转”的意思,也就是说 Spring 是⼀个“控制反转”的容器。

1.1控制反转推导

这个控制反转怎么理解呢?我们来推导一下这个过程:

我们现在构建⼀辆“⻋”的程序,我们的实现思路和代码实现是这样的:

轮胎的尺⼨的固定的,然⽽随着对的⻋的需求量越来越⼤,个性化需求也会越来越多,这时候我们就需要加⼯多种尺⼨的轮胎,那这个时候就要对上面的程序进⾏修改了,修改后的代码如下所示:

从上面的代码中可以看出传统写法的缺陷:代码耦合性太高

那上述问题我们可以怎么解决呢?

这就好⽐我们打造⼀辆完整的汽车,传统的方式是所有的配件都是⾃⼰造,那么当客户需求发⽣改变的时候,⽐如轮胎的尺⼨不再是原来的尺⼨了,那我们要⾃⼰动⼿来改了,但如果我们是把轮胎外包出去,那么即使是轮胎的尺⼨发⽣变变了,我们只需要向代理⼯⼚下订单就⾏了,我们⾃身是不需要出⼒的。

所以:我们可以尝试不在每个类中自己创建下级类,如果⾃⼰创建下级类就会出现当下级类发⽣改变操作,⾃⼰也要跟着修改。
此时,我们只需要将原来由自己创建的下级类,改为传递的方式(也就是注入的方式),因为我们不需要在当前类中创建下级类了,所以下级类即使发生变化(创建或减少参数),当前类本身也⽆需修改任何代码,这样就完成了程序的解耦。

代码实现思路如下:

总结对比一下:

执行顺序:

在传统的代码中对象创建顺序是:Car -> Framework -> Bottom -> Tire
改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car

通⽤程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了Framework,Framework 创建并创建了 Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再是上级对象创建并控制下级对象了,⽽是下级对象把注⼊将当前对象中,下级的控制权不再由上级类控制了,这样即使下级类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实
现思想。

上述过程不知道各位小伙伴能不能理解,但总结来说就是传统的写法所有的东西都是由程序去控制创建的,改进后的写法是由调用者自行控制创建对象 , 把主动权交给了调用者 . 程序不用去管怎么创建,怎么实现了 . 它只负责提供一个接口 .。

这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 。

1.2、IOC的本质:

控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

1.2.1、DI依赖注入

说到 IoC 不得不提的⼀个词就是“DI”,DI 是 Dependency Injection 的缩写,翻译成中⽂是“依赖注
⼊”的意思。
所谓依赖注⼊,就是由 IoC 容器在运⾏期间,动态地将某种依赖关系注⼊到对象之中。所以,依
赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过引⼊ IoC 容
器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。
IoC 是“⽬标”也是⼀种思想,⽽⽬标和思想只是⼀种指导原则,最终还是要有可⾏的落地⽅案,⽽ DI就属于具体的实现。

DI 概念说明:

将对象存放到容器中的好处:将对象存储在 IoC 容器相当于将以后可能⽤的所有⼯具制作好都放到仓库中,需要的时候直接取就⾏了,⽤完再把它放回到仓库。⽽ new 对象的⽅式相当于,每次需要⼯具了,才现做,⽤完就扔掉了也不会保存,下次再⽤的时候还得重新做,这就是 IoC 容器和普通程序开发的区别

二、创建有一个Spring项目

1、配置maven国内源

2、创建spring项目

<dependencies>
        <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.3.RELEASE</version>
</dependency>
<dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>5.2.3.RELEASE</version>
</dependency>
</dependencies>

按照上述步骤配置完成,启动成功不报错,那么一个spring项目就创建好了,接下来我们体验一下Spring是如何获取和使用Bean的。

3、获取和使用Spring对象

3.1、添加 Spring 配置⽂件 spring-config.xml

在创建好的项⽬中添加 Spring 配置⽂件 spring-config.xml,将此⽂件放到 resources 的根⽬录下

Spring 配置⽂件的固定格式为以下内容(以下内容⽆需记忆,只需要保存到⾃⼰可以找到的地

就可以了,因为它是固定不变的)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans htt
p://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

3.2、将Bean对象存储到Spring(IOC容器)

【解释一下:这里的我们正常创建一个类是这么写的:类型   变量名 = new 类型();bean中的 id 相当于变量名,class 相当于 new的对象】

3.2、从容器中获取Bean对象

获取并使⽤ Bean 对象,分为以下 3 步:

  1. 得到 Spring 上下文对象,因为对象都交给 Spring 管理了,所以获取对象要从 Spring 中获取,那么就得先得到 Spring 的上下文。
  2. 通过 Spring 上下文,获取某⼀个指定的 Bean 对象。
  3. 使⽤ Bean 对象。

如果取多个 Bean 的话重复以上第 2、3 步骤。

除了 ApplicationContext 之外,我们还可以使⽤ BeanFactory 来作为 Spring 的上下⽂,如下代码所示:

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("springconfig.xml"));

ApplicationContext 和BeanFactory 的区别

3.3、getBean ⽅法的更多⽤法

getBean() ⽅法有很多种重载⽅法,我们也可以使⽤其他⽅式来获取 Bean 对象

三、Spring 更简单的读取和存储对象——注解

3.1、配置扫描路径

前置工作,在之前的spring-config.xml文件中配置bean的扫描路径,如果不配置,后面所有的操作都不会生效。

3.2、注解

想要将对象存储在 Spring 中,有两种注解类型可以实现:

  • 类注解:@Controller、@Service、@Repository、@Component、@Configuration。
  • 方法注解:@Bean。

3.2.1、五类注解

@Controller // 将对象存储到 Spring 中
public class UserController {
public void sayHi(String name) {
System.out.println("Hi," + name);
}
}public class Application {
public static void main(String[] args) {
// 1.得到 spring 上下⽂
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
// 2.得到 bean
UserController userController = (UserController) context.getBean(
"userController");
// 3.调⽤ bean ⽅法
userController.sayHi("Bit");
}
}========================
@Service
public class UserService {
public void sayHi(String name) {
System.out.println("Hi," + name);
}
}class App {
public static void main(String[] args) {
// 1.得到 spring 上下⽂
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
// 2.得到 bean
UserService userService = (UserService) context.getBean("userServi
ce");
// 3.调⽤ bean ⽅法
userService.sayHi("Bit");
}
}
=======================================
@Repository
public class UserRepository {
public void sayHi(String name) {
System.out.println("Hi," + name);
}
}class App {
public static void main(String[] args) {
// 1.得到 spring 上下⽂
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
// 2.得到某个 bean
UserRepository userRepository = (UserRepository) context.getBean(
"userRepository");
// 3.调⽤ bean ⽅法
userRepository.sayHi("Bit");
}
}
=================================================
@Component
public class UserComponent {
public void sayHi(String name) {
System.out.println("Hi," + name);
}
}class App {
public static void main(String[] args) {
// 1.得到 spring 上下⽂
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
// 2.得到某个 bean
UserComponent userComponent = (UserComponent) context.getBean("use
rComponent");
// 3.调⽤ bean ⽅法
userComponent.sayHi("Bit");
}
}
=======================
@Configuration
public class UserConfiguration {
public void sayHi(String name) {
System.out.println("Hi," + name);
}
}
class App {
public static void main(String[] args) {
// 1.得到 spring 上下⽂
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
// 2.得到某个 bean
UserConfiguration userConfiguration = (UserConfiguration) context.
getBean("userConfiguration");
// 3.调⽤ bean ⽅法
userConfiguration.sayHi("Bit");
}
}

观察上述代码,可以发现,这五个注解的功能是一样的,那么我们为什么要用那么多个注解呢?用一个不就行了?

这和为什么每个省/市都有⾃⼰的⻋牌号是⼀样的?⽐如陕⻄的⻋牌号就是:陕X:XXXXXX,北京的⻋牌号:京X:XXXXXX,⼀样。甚⾄⼀个省不同的县区也是不同的,⽐如⻄安就是,陕A:XXXXX,咸阳:陕B:XXXXXX,宝鸡,陕C:XXXXXX,⼀样。这样做的好处除了可以节约号码之外,更重要的作⽤是可以直观的标识⼀辆⻋的归属地
同理,我们使用那么多的类注解也是相同的原因,就是让程序员看到类注解之后,就能直接了解当前类的⽤途:

这五类注解的用途如下:

@Controller   【控制器】 校验参数的合法性(相当于安检系统)

@Service       【服务】业务组装(客服中心)

@Repository 【数据持久层】实际业务处理中心(实际办理业务的)

@Component【组件】工具类层(基础的工具)

@Configuration【配置层】配置

程序的工程分层,调⽤流程如下:

这五个注解之间的关系:

我们查看源码后发现,其实这些注解⾥⾯都有⼀个注解 @Component,说明它们本身就是属于 @Component 的“子类”

方法注解@Bean

类注解是添加到某个类上的,而方法注解是放到某个⽅法上的,如以下代码的实现:


3.3、Bean命名规则

3.3.1、@Bean的重命名:

3.4、获取 Bean 对象(对象装配)

获取 bean 对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注⼊
对象装配(对象注⼊)的实现⽅法以下 3 种:

  1. 属性注⼊
  2.  构造⽅法注⼊
  3. Setter 注⼊

3.4.1、 属性注⼊

属性注⼊是使用 @Autowired 实现的,将 Service 类注⼊到 Controller 类中。
Service 类的实现代码如下:

@Service
public class UserService {public User getUser(Integer id) {
// 伪代码,不连接数据库
User user = new User();
user.setId(id);
user.setName("Java-" + id);
return user;
}
}

Controller 类的实现代码如下:

@Controller
public class UserController {
// 注⼊⽅法1:属性注⼊
@Autowired
private UserService userService;   //属性注入的核心代码public User getUser(Integer id) {
return userService.getUser(id);
}
}

获取 Controller 中的 getUser ⽅法:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserControllerTest {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
UserController userController = context.getBean(UserController.cla
ss);
System.out.println(userController.getUser(1).toString());
}
}

最终结果如下:

3.4.1.1、注意:  同类型的Bean存储到容器多个,获取时会报错

@Component
public class Users {
@Bean
public User user1() {
User user = new User();
user.setId(1);
user.setName("Java");
return user;
}
@Bean
public User user2() {
User user = new User();
user.setId(2);
user.setName("MySQL");
return user;
}

在另⼀个类中获取 User 对象,代码和运行结果如下:

解决方案:

1. 使⽤ @Resource(name="")
2. 使⽤ @Qualifier("")

3.4.1.2、属性注入的优缺点:

3.4.2、Setter 注入

Setter 注入和属性的 Setter ⽅法实现类似,只不过在设置 set ⽅法的时候需要加上 @Autowired 注解(不能省),Controller 类的实现代码如下:

@Controller
public class UserController3 {
// 注⼊⽅法3:Setter注⼊
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public User getUser(Integer id) {
return userService.getUser(id);
}
}

3.4.1.1、Setter注入优缺点:

3.4.3、构造方法注入

构造⽅法注⼊是在类的构造⽅法中实现注⼊,Controller 类的实现代码如下:

@Controller
public class UserController2 {
// 注⼊⽅法2:构造⽅法注⼊
private UserService userService;
@Autowired
public UserController2(UserService userService) {
this.userService = userService;
}
public User getUser(Integer id) {
return userService.getUser(id);
}
}

注意:如果只有⼀个构造⽅法,那么 @Autowired 注解可以省略,如下图所示:

3.4.3.1、构造方法注入优缺点:

Spring为什么使用三级缓存解决循环依赖?_哔哩哔哩_bilibili

3.2.4、三种注入优缺点分析

  • 属性注⼊的优点是简洁,使用方便;缺点是只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,并且只有在使⽤的时候才会出现 NPE(空指针异常)。
  • 构造⽅法注⼊是 Spring 推荐的注入方式,它的缺点是如果有多个注⼊会显得⽐较臃肿,但出现这种情况你应该考虑⼀下当前类是否符合程序的单⼀职责的设计模式了,它的优点是通⽤性,在使⽤之前⼀定能把保证注⼊的类不为空。
  • Setter ⽅式是 Spring 前期版本推荐的注⼊⽅式,但通⽤性不如构造⽅法,所有 Spring 现版本已经推荐使⽤构造⽅法注⼊的⽅式来进⾏类注入了。

 @Resource:另⼀种注⼊关键字
在进⾏类注⼊时,除了可以使⽤ @Autowired 关键字之外,我们还可以使⽤ @Resource 进⾏注⼊:

@Controller
public class UserController {
// 注⼊
@Resource
private UserService userService;
public User getUser(Integer id) {
return userService.getUser(id);
}
}

@Autowired 和 @Resource 的区别

四、Bean 作⽤域和⽣命周期

4.1、作用域

限定程序中变量的可⽤范围叫做作⽤域,或者说在源代码中定义变量的某个区域就叫做作⽤域。
⽽ Bean 的作⽤域是指 Bean 在 Spring 整个框架中的某种⾏为模式,
⽐如 singleton 单例作⽤域,就表示 Bean 在整个 Spring 中只有⼀份,它是全局共享的,那么当其他⼈修改了这个值之后,那么另⼀个⼈读取到的就是被修改的值
Spring 容器在初始化⼀个 Bean 的实例时,同时会指定该实例的作⽤域。

Spring有 6 种作⽤域,最后四种是基于 Spring MVC ⽣效的:
1. singleton:单例作⽤域(单例模式,默认的作用域)
2. prototype:原型作⽤域(原型模式,多例作⽤域)
3. request:请求作⽤域,只适用于SpringMVC项目(Spring Web)
4. session:回话作⽤域,一个Http会话共享一个Bean。只适用于SpringMVC项目(Spring Web)
5. application:应用作用域(全局作用域)表示的是一个Context容器共享一个作用域。只适用于SpringMVC项目(Spring Web)
6. websocket:HTTP WebSocket 作⽤域,只适用于websocket作用域。

单例作用域(singleton) VS 全局作用域(application)

singleton 是 Spring Core 的作⽤域;application 是 Spring Web 中的作用域;
singleton 作⽤于 IoC 的容器,而 application 作⽤于 Servlet 容器。

4.2、设置作⽤域

使⽤ @Scope 标签就可以⽤来声明 Bean 的作⽤域,⽐如设置 Bean 的作⽤域,如下代码所示:

@Component
public class Users {
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean(name = "u1")
public User user1() {
User user = new User();
user.setId(1);
user.setName("Java"); 
return user;
}
}

@Scope 标签既可以修饰方法也可以修饰类,@Scope 有两种设置⽅式:

  1. 直接设置值:@Scope("prototype")
  2. 使⽤枚举设置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

4.3、Spring 执⾏流程

启动 Spring 容器 -> 实例化 Bean(分配内存空间,从⽆到有) -> Bean 注册到 Spring 中(存操作) -> 将 Bean 装配到需要的类中(取操作)。
4.4、Bean 生命周期
所谓的⽣命周期指的是⼀个对象从诞⽣到销毁的整个生命过程,我们把这个过程就叫做⼀个对象的生命周期。
Bean 的⽣命周期分为以下 5 ⼤部分:
1.实例化 Bean(为 Bean 分配内存空间)
2.设置属性(Bean 注⼊和装配)
3.Bean 初始化

实现了各种 Aware 通知的⽅法,如 BeanNameAware、BeanFactoryAware、
ApplicationContextAware 的接⼝⽅法;
执⾏ BeanPostProcessor 初始化前置⽅法;
执⾏ @PostConstruct 初始化⽅法,依赖注⼊操作之后被执⾏;
执⾏⾃⼰指定的 init-method ⽅法(如果有指定的话);
执⾏ BeanPostProcessor 初始化后置⽅法。


4.使⽤ Bean
5.销毁 Bean

4.4、实例化和初始化的区别


实例化和属性设置是 Java 级别的系统“事件”,其操作过程不可人工干预和修改;⽽初始化是给开发者提供的,可以在实例化之后,类加载完成之前进行自定义“事件”处理


以上就是本文分享的主要内容,对你有帮助的话,可以点个赞哦~~

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

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

相关文章

类的加载过程

清楚每个环节的操作过程就可以了 1.加载Loading 加载过程&#xff1a; 通过一个类的全限定名获取定义此类的二进制字节流将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构在内存中生成一个代表这个类的java.lang.class对象&#xff0c;作为方法区这个类的各种数…

Gitea--私有git服务器搭建详细教程

一.官方文档 https://docs.gitea.com/zh-cn/说明 gitea 是一个自己托管的Git服务程序。他和GitHub, Gitlab等比较类似。他是从 Gogs 发展而来&#xff0c;gitea的创作团队重新fork了代码&#xff0c;并命名为giteagitea 功能特性多&#xff0c;能够满足我们所有的的代码管理需…

nowcoder NC10 大数乘法

题目链接&#xff1a; https://www.nowcoder.com/practice/c4c488d4d40d4c4e9824c3650f7d5571?tpId196&tqId37177&rp1&ru/exam/company&qru/exam/company&sourceUrl%2Fexam%2Fcompany&difficultyundefined&judgeStatusundefined&tags&tit…

《异常检测——从经典算法到深度学习》22 Kontrast: 通过自监督对比学习识别软件变更中的错误

《异常检测——从经典算法到深度学习》 0 概论1 基于隔离森林的异常检测算法 2 基于LOF的异常检测算法3 基于One-Class SVM的异常检测算法4 基于高斯概率密度异常检测算法5 Opprentice——异常检测经典算法最终篇6 基于重构概率的 VAE 异常检测7 基于条件VAE异常检测8 Donut: …

Unity中Shader的屏幕坐标

文章目录 前言一、屏幕坐标1、屏幕像素的坐标2、屏幕坐标归一化 二、在Unity中获取 当前屏幕像素 和 总像素1、获取屏幕总像素,使用_ScreenParams参数2、获取当前片段上的像素怎么使用:在片元着色器传入参数时使用 前言 Unity中Shader的屏幕坐标 一、屏幕坐标 1、屏幕像素的坐…

非科班菜鸡算法学习记录 | 代码随想录算法训练营第58天|| 单调栈! 739. 每日温度 496.下一个更大元素 I

739. 每日温度 输入一个数组&#xff0c;找比i天温度高的第一天 知识点&#xff1a;单调栈 状态&#xff1a;看思路自己写 思路&#xff1a; 看自己写的注释&#xff0c;维护一个单调栈 // 版本一 class Solution { public:vector<int> dailyTemperatures(vector<…

视频导出文件太大如何变小?缩小视频这样做

作为一名视频制作爱好者&#xff0c;我们经常需要导出视频文件&#xff0c;但是&#xff0c;有时候我们会发现导出的视频文件太大&#xff0c;给上传和分享带来很大的不便。那么&#xff0c;如何将视频文件变小呢&#xff1f;下面将为你介绍三个方法&#xff0c;让你轻松解决视…

React 18 使用 Context 深层传递参数

参考文章 使用 Context 深层传递参数 通常来说&#xff0c;会通过 props 将信息从父组件传递到子组件。但是&#xff0c;如果必须通过许多中间组件向下传递 props&#xff0c;或是在应用中的许多组件需要相同的信息&#xff0c;传递 props 会变的十分冗长和不便。Context 允许…

Web后端开发(请求响应)上

请求响应的概述 浏览器&#xff08;请求&#xff09;<--------------------------(HTTP协议)---------------------->&#xff08;响应&#xff09;Web服务器 请求&#xff1a;获取请求数据 响应&#xff1a;设置响应数据 BS架构&#xff1a;浏览器/服务器架构模式。…

阿里云部署开源MQTT平台mosquitto的docker操作

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的消息传输协议&#xff0c;广泛用于物联网和传感器网络中。Mosquitto是一个流行的开源MQTT代理&#xff0c;可以在Docker中进行配置和部署。本文将详细介绍如何在Docker中配置Mosquitto MQTT代理…

电梯SIP-IP五方对讲管理系统

电梯SIP-IP五方对讲管理系统 是深圳锐科达精心打磨的一款IP数字信号对讲设备&#xff0c;是在传统电梯对讲系统基础上的一次全新升级&#xff0c;突破了模拟、FM调频系统存在的技术障碍&#xff0c;实现联网;在模/数交替的过程中&#xff0c;继承了模拟、FM调频系统的优点&…

Python实现猎人猎物优化算法(HPO)优化卷积神经网络回归模型(CNN回归算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 猎人猎物优化搜索算法(Hunter–prey optimizer, HPO)是由Naruei& Keynia于2022年提出的一种最新的…

Krahets 笔面试精选 88 题——40. 组合总和 II

使用深度搜索的方法&#xff1a; 由于题目说候选数组中的每个数字在每个组合只能出现一次&#xff0c;所以&#xff0c;为了避免重复&#xff0c;在开始之前对候选数组进行升序排序&#xff0c;这样优先选择小的数&#xff0c;如果当前的数都小于目标值&#xff0c;则后面的数就…

Android MQTT:实现设备信息上报与远程控制

Android MQTT&#xff1a;实现设备信息上报与远程控制 1. 介绍 1.1 MQTT是什么&#xff1f; MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的消息传输协议&#xff0c;最初由IBM开发&#xff0c;用于连接远程设备与服务器之间的通信。它在物…

day2_C++

day2_C 代码题思维导图 代码题 #include using namespace std;#define MAX 50struct StuData {private:int scoreArr[MAX];int num;public:void setNum(int num);void input();void sort();void show();int getnum();};void StuData::setNum(int num){this->num num; }vo…

第3章 【MySQL】字符集和比较规则

3.1 字符集和比较规则简介 3.1.1 字符集简介 如何存储字符串&#xff1f;需要建立字符与二进制数据的映射关系。建立这个关系需要&#xff1a; 1.把哪些字符映射成二进制数据&#xff1f; 2.怎么映射&#xff1f; 将一个字符映射成一个二进制数据的过程也叫做 编码 &#…

[杂谈]-快速了解直接内存访问 (DMA)

快速了解直接内存访问 (DMA) 文章目录 快速了解直接内存访问 (DMA)1、使用 DMA 需要什么&#xff1f;2、DMA介绍3、DMA 中的数据传输如何进行&#xff1f;4、DMA接口5、DMAC 控制器寄存器6、DMA 控制器编程模式6.1 突发模式&#xff08;Burst Mode&#xff09;6.2 循环窃取模式…

MATLAB 动态图GIF

MATLAB 动态图GIF 前言一、创建动态图&#xff08;动态曲线、动态曲面&#xff09;1. 创建动画曲线&#xff08;MATLAB animatedline函数&#xff09;2. 创建动画曲面 二. 保存动态图三、完整示例1. 动态曲线&#xff08; y s i n ( x ) ysin(x) ysin(x)&#xff09;2. 动态曲…

Linux之权限

目录 一、shell运行原理 二、权限 1、对人操作 2、对角色和文件操作 修改权限&#xff08;改属性&#xff09;&#xff1a; ①ugo- ②二进制数的表示 修改权限&#xff08;改人&#xff09;&#xff1a; 三、权限的相关问题 1、目录的权限 2、umask 3、粘滞位 一、s…

LeetCode 202 快乐数

题目链接 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 法一&#xff1a;哈希 使用哈希表循环判断每次经过平方和的数&#xff0c;如果为1则直接返回true&#xff0c;若之前存在过但不为1则直接返回false 代码 class Solution { public:// 计算…