spring loCDI 详解

news2024/11/16 19:30:43

文章目录

  • 一、IoC & DI 基本知识
    • 1.1 IoC 的基本概念:
    • 1.2 IoC 的优势:
    • 1.3 DI 介绍:
  • 二、IoC 详解
    • 2.1 Spring 容器:
    • 2.2 被存储 Bean 的命名约定:
    • 2.3 Bean 的存储方式:
      • 2.3.1 五大类注解:
        • 2.3.1.1 @Controller(控制器存储):
        • 2.3.1.2 @Service(服务存储):
        • 2.3.1.3 @Repository(仓库存储):
        • 2.3.1.4 @Configuration(配置存储):
        • 2.3.1.5 @Component(组件存储):
        • 2.3.1.6 类注解之间的关系:
      • 2.3.2 方法注解(@Bean):
    • 2.4 Bean 重命名:
      • 2.4.1 五大类注解重命名:
      • 2.4.2 方法注解重命名:
  • 三、DI 详解(@Autowired)
    • 3.1 属性注入:
    • 3.2 Setter 注入:
    • 3.3 构造方法注入:
    • 3.4 三种注入优缺点:
    • 3.5 处理一个类多个对象的注入情况:
      • 3.5.1 @Primary:
      • 3.5.2 @Qualifier:
      • 3.5.3 @Resource:

一、IoC & DI 基本知识

使用一句话概括 Spring:

Spring 是包含了众多工具方法的 IoC 容器。

1.1 IoC 的基本概念:

其实 IoC 我们在前面已经使用了,我们在前面讲到,在类上面添加 @RestController 和 @Controller 注解,就是把这个对象交给 Spring 管理,Spring 框架启动时就会加载该类。把对象交给 Spring 管理,就是 IoC 思想。

IoC:Inversion of Control (控制反转),也就是说 Spring 是一个"控制反转"的容器。

控制反转的概念:

控制反转更准确的说是控制权反转。当需要某个对象时,传统开发模式中需要自己通过 new 创建对象,现在不需要再进行创建,把创建对象的任务交给容器,程序中只需要依赖注入(Dependency Injection,DI)就可以。

1.2 IoC 的优势:

资源不由使用资源的双方管理,而由不使用资源的第三方管理,这可以带来很多好处。

  1. 资源集中管理,实现资源的可配置和易管理。

  2. 降低了使用资源双方的依赖程度,也就是我们说的解耦合。

Spring 就是一种 IoC 容器,帮助我们来做了这些资源管理。

1.3 DI 介绍:

DI:Dependency Injection(依赖注入)。

容器在运行期间,动态的为应用程序提供运行时所依赖的资源,称之为依赖注入。

IoC 是一种思想,也是"目标",而思想只是一种指导原则,最终还是要有可行的落地方案,而 DI 就属于具体的实现。所以也可以说,DI 是 IoC 的一种实现。

二、IoC 详解

在 Spring 框架中,Bean 和对象是等价的 。也就是说,下面我们提到的 Bean 其实就是指对象。

2.1 Spring 容器:

这里我们来学习一下如何从 Spring 容器中获取对象。

假设 UserController 对象已经被存储在 Spring 容器中。

我们通过下面的代码即可获取到 UserController 对象。

@SpringBootApplication
public class Spring20240928iocApplication {
    public static void main(String[] args) {
        //获取 Spring 上下文对象
        ApplicationContext context = SpringApplication.run(Spring20240928iocApplication.class, args);
        //从 Spring 上下文中获取对象
        UserController userController = context.getBean(UserController.class);
        //使用对象
        userController.sayHi();
    }
}

ApplicationContext 翻译过来就是:Spring 上下文。

因为对象都交给 Spring 管理了,所以获取对象要从 Spring 中获取,那么就得先得到 Spring 的上下文。

关于 getBean 要传递的参数,下面有详细解释。

  • getBean 的详解:

上述代码是根据类型来查找对象。

如果 Spring 容器中,同一个类型存在多个 bean 的话,怎么来获取呢?

ApplicationContext 也提供了其他获取 bean 的方式,ApplicationContext 获取 bean 对象的功能,是父类 BeanFactory 提供的功能。

public interface BeanFactory {
 
 //以上省略... 
 
 // 1. 根据bean名称获取bean 
 Object getBean(String var1) throws BeansException;
 // 2. 根据bean名称和类型获取bean 
 <T> T getBean(String var1, Class<T> var2) throws BeansException;
 // 3. 按bean名称和构造函数参数动态创建bean,只适⽤于具有原型(prototype)作⽤域的bean 
 Object getBean(String var1, Object... var2) throws BeansException;
 // 4. 根据类型获取bean 
 <T> T getBean(Class<T> var1) throws BeansException;
 // 5. 按bean类型和构造函数参数动态创建bean, 只适⽤于具有原型(prototype)作⽤域的
bean
 <T> T getBean(Class<T> var1, Object... var2) throws BeansException;
 
 //以下省略... 
}

常用的是上述1,2,4种,这三种方式,获取到的 bean 是一样的。

其中 1,2 种都涉及到根据名称来获取对象。

bean 的名称是什么呢?

2.2 被存储 Bean 的命名约定:

我们看下官方文档的说明:https://docs.spring.io/spring-framework/reference/core/beans/definition.html#beans-beanname

image-20240930150345091

程序开发人员不需要为 bean 指定名称,如果没有显式的提供名称,Spring 容器将为该 bean 生成唯一的名称。

Bean 默认名称的具体生成规则如下:

  • 五大类注解:

**普通:类名的小驼峰表示法。**例如:类名:UserController,Bean 的名称为:userController。

**如果前两位为大写:类名。**例如:类名:UController,Bean 的名称为:UController。

  • 方法注解(@Bean):

**Bean 的名称为方法名。**例如:方法名:getUserInfo,Bean 的名称为:getUserInfo。

上面都是 spring 自动帮助我们生成的,如果觉得不合适,程序员可以自己指定,只要不重复就行。

2.3 Bean 的存储方式:

共有两类注解类型可以实现:

  1. 类注解:@Controller、@Service、@Repository、@Configuration、@Component。
  2. 方法注解:@Bean。

2.3.1 五大类注解:

2.3.1.1 @Controller(控制器存储):

使用 @Controller 存储 bean 的代码,如下所示:

import org.springframework.stereotype.Controller;

@Controller // 将对象存储到 Spring 中
public class UserController {
    public void sayHi(){
        System.out.println("hi,UserController...");
    }
}

从 Spring 容器中获取对象。

@SpringBootApplication
public class Spring20240928iocApplication {
    public static void main(String[] args) {
        //获取 Spring 上下文对象
        ApplicationContext context = SpringApplication.run(Spring20240928iocApplication.class, args);
        //从 Spring 上下文中获取对象
        UserController userController = context.getBean(UserController.class);
        //使用对象
        userController.sayHi();
    }
}

效果如下:

image-20240930124238715
2.3.1.2 @Service(服务存储):

使用 @Service 存储 bean 的代码,如下所示:

@Service
public class UserService {
    public void sayHi(){
        System.out.println("hello Service~");
    }
}

从 Spring 容器中获取对象。

@SpringBootApplication
public class Spring20240928iocApplication {
    public static void main(String[] args) {
        //获取 Spring 上下文对象
        ApplicationContext context = SpringApplication.run(Spring20240928iocApplication.class, args);
        //从 Spring 上下文中获取对象
        UserService userService = context.getBean(UserService.class);
        //使用对象
        userService.sayHi();
    }
}

效果如下:

image-20240930124639168
2.3.1.3 @Repository(仓库存储):

使用 @Repository 存储 bean 的代码,如下所示:

@Repository
public class UserRepository {
    public void sayHi(){
        System.out.println("Hi,Repository~");
    }
}

从 Spring 容器中获取对象。

@SpringBootApplication
public class Spring20240928iocApplication {
    public static void main(String[] args) {
        //获取 Spring 上下文对象
        ApplicationContext context = SpringApplication.run(Spring20240928iocApplication.class, args);
        //从 Spring 上下文中获取对象
        UserRepository userRepository = context.getBean(UserRepository.class);
        //使用对象
        userRepository.sayHi();
    }
}

效果如下:

image-20240930125226452
2.3.1.4 @Configuration(配置存储):

使用 @Configuration 存储 bean 的代码,如下所示:

@Configuration
public class UserConfiguration {
    public void sayHi(){
        System.out.println("hi,UserConfiguration...");
    }
}

从 Spring 容器中获取对象。

@SpringBootApplication
public class Spring20240928iocApplication {
    public static void main(String[] args) {
        //获取 Spring 上下文对象
        ApplicationContext context = SpringApplication.run(Spring20240928iocApplication.class, args);
        //从 Spring 上下文中获取对象
        UserConfiguration userConfiguration = context.getBean(UserConfiguration.class);
        //使用对象
        userConfiguration.sayHi();
    }
}

效果如下:

image-20240930125837295
2.3.1.5 @Component(组件存储):

使用 @Component 存储 bean 的代码,如下所示:

@Component
public class UserComponent {
    public void sayHi(){
        System.out.println("hi,UserComponent...");
    }
}

从 Spring 容器中获取对象。

@SpringBootApplication
public class Spring20240928iocApplication {
    public static void main(String[] args) {
        //获取 Spring 上下文对象
        ApplicationContext context = SpringApplication.run(Spring20240928iocApplication.class, args);
        //从 Spring 上下文中获取对象
        UserComponent userComponent = context.getBean(UserComponent.class);
        //使用对象
        userComponent.sayHi();
    }
}

效果如下:

image-20240930130255621

为什么要这么多类注解?

这个也是和我们前面讲的应用分层是呼应的。让程序员看到类注解之后,就能直接了解当前类的用途。

  • @Controller:控制层。接收请求,对请求进行处理,并进行响应。
  • @Servie:业务逻辑层。处理具体的业务逻辑。
  • @Repository:数据层,也称为持久层。负责数据访问操作。
  • @Configuration:配置层。处理项目中的一些配置信息。
  • @Component:组件层。实际开发中,如果实在分不清是什么层的,就用 @Component(除了控制层,@Controller 有特殊的含义)。

程序的应用分层,调用流程如下:

image-20240930131117962
2.3.1.6 类注解之间的关系:

查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:

image-20240930131647518

其实这些注解里面都有一个注解 @Component ,说明它们本身就是属于 @Component 的"子类"。

@Component 是一个元注解,也就是说可以注解其他类注解,如 @Controller,@Service ,@Repository 等。这些注解被称为 @Component 的衍生注解。

@Controller,@Service 和 @Repository 用于更具体的用例(分别在表现层,业务逻辑层,数据层),在开发过程中,如果你要在业务逻辑层使用 @Component 或 @Service,显然 @Service 是更好的选择。比如杯子有喝水杯,刷牙杯等,但是我们更倾向于在日常喝水时使用水杯,洗漱时使用刷牙杯。

2.3.2 方法注解(@Bean):

类注解是添加到某个类上的,但是存在两个问题:

  1. 使用外部包里的类,没办法添加类注解。
  2. 一个类,需要多个对象,比如多个数据源。

这种场景,我们就需要使用方法注解 @Bean。

注意:方法注解要配合类注解使用。

在 Spring 框架的设计中,方法注解 @Bean 要配合类注解才能将对象正常的存储到 Spring 容器中。

如下代码所示:

@Configuration
public class UserConfig {
    @Bean
    public UserInfo getUserInfo1(){
        return new UserInfo(1,"zhangsan");
    }
}

通过上面这段代码的写法,我们就能获取到外部包里的类。无需在外部包里面加上类注解。

  • 同一个类,定义多个对象:
@Configuration
public class UserConfig {
    @Bean
    public UserInfo getUserInfo1(){
        return new UserInfo(1,"zhangsan");
    }
    @Bean
    public UserInfo getUserInfo2(){
        return new UserInfo(2,"lisi");
    }
}

通过 Spring 容器,获取对象。

@SpringBootApplication
public class Spring20240928iocApplication {
    public static void main(String[] args) {
        //获取 Spring 上下文对象
        ApplicationContext context = SpringApplication.run(Spring20240928iocApplication.class, args);
        //获取对应的对象
        UserInfo getUserInfo1 = (UserInfo)context.getBean("getUserInfo1");
        UserInfo getUserInfo2 = (UserInfo) context.getBean("getUserInfo2");
        //进行打印
        System.out.println(getUserInfo1);
        System.out.println(getUserInfo2);
    }
}

效果如下:

image-20240930151701751

可以看到,@Bean 可以针对同一个类,定义多个对象。

这时如果通过类型来获取 Bean 就会报错,显示这个类没有唯一的 Bean。

image-20240930153536495

2.4 Bean 重命名:

2.4.1 五大类注解重命名:

直接在注解里面加上名字即可,或者加上 value = 名字。

@Repository("u1")
public class UserRepository {
    public void sayHi(){
        System.out.println("Hi,Repository~");
    }
}

获取 Bean。

@SpringBootApplication
public class Spring20240928iocApplication {
    public static void main(String[] args) {
        //获取 Spring 上下文对象
        ApplicationContext context = SpringApplication.run(Spring20240928iocApplication.class, args);
        
        UserRepository userRepository = context.getBean("u1", UserRepository.class);
        
        userRepository.sayHi();
    }
}

效果如下:

image-20240930154221500

2.4.2 方法注解重命名:

可以通过设置 name 属性给 Bean 对象进行重命名操作,如下代码所示:

@Configuration
public class UserConfig {
    @Bean(name = {"h1","h2"})
    public UserInfo getUserInfo1(){
        return new UserInfo(1,"zhangsan");
    }
}

其中 name 可以省略(只有一个参数的情况),如果只有一个名称时{},也可以省略。

@SpringBootApplication
public class Spring20240928iocApplication {
    public static void main(String[] args) {
        //获取 Spring 上下文对象
        ApplicationContext context = SpringApplication.run(Spring20240928iocApplication.class, args);

        UserInfo userInfo = context.getBean("h1", UserInfo.class);

        System.out.println(userInfo);

    }
}

image-20240930154804164

三、DI 详解(@Autowired)

依赖注入是一个过程,是指 IoC 容器在创建 Bean 时,去提供运行时所依赖的资源,而资源指的就是对象。、

关于依赖注入,Spring 也给我们提供了三种方式:

  1. 属性注入(Field Injection)

  2. Setter 注入(Setter Injection)

  3. 构造方法注入(Constructor Injection)

后续的注入演示代码将采用 Service 类注入到 Controller 类中。为了帮助大家理解,下面先给出 Service 类。

@Service
public class UserService {
    public void sayHi(){
        System.out.println("hello Service~");
    }
}

3.1 属性注入:

属性注入是使用 @Autowired 实现的。

Controller 类的实现代码如下:

@Controller // 将对象存储到 Spring 中
public class UserController {
    @Autowired
    private UserService userService;
    public void sayHi(){
        System.out.println("hi,UserController...");
        userService.sayHi();
    }
}

调用 Controller 中的 sayHi 方法:

@SpringBootApplication
public class Spring20240928iocApplication {
    public static void main(String[] args) {
        //获取 Spring 上下文对象
        ApplicationContext context = SpringApplication.run(Spring20240928iocApplication.class, args);
        
        UserController userController = context.getBean(UserController.class);
        
        userController.sayHi();
    }
}

效果如下:

image-20240930160443244

3.2 Setter 注入:

Setter 注入和属性的 Setter 方法实现类似,只不过在设置 set 方法的时候,需要加上 @Autowired 注解,如下代码所示:

@Controller // 将对象存储到 Spring 中
public class UserController {

    private UserService userService;
    @Autowired
    public void setUserService(UserService userService){
        this.userService = userService;
    }
    public void sayHi(){
        System.out.println("hi,UserController...");
        userService.sayHi();
    }
}

由于获取 Bean 的方式和效果是一样的所以 Setter 注入和构造方法注入,就不再赘述。

3.3 构造方法注入:

构造方法注入是在类的构造方法中实现注入,如下代码所示:

@Controller // 将对象存储到 Spring 中
public class UserController {

    private UserService userService;

    @Autowired
    public UserController(UserService userService){
        this.userService = userService;
    }
    public void sayHi(){
        System.out.println("hi,UserController...");
        userService.sayHi();
    }
}

注意:如果类只有一个构造方法,那么 @Autowired 注解可以省略,如果类中有多个构造方法, 那么需要添加上 @Autowired 来明确指定到底使用哪个构造方法。

3.4 三种注入优缺点:

  • 属性注入:

优点:简洁,使用方便。

缺点:

  1. 只能用于 IoC 容器,如果是非 IoC 容器不可用。

  2. 不能注入一个 Final 修饰的属性。

  • Setter注入(Spring 3.X推荐):

优点:方便在类实例之后,重新对该对象进行配置或者注入。

缺点:不能注入一个 Final 修饰的属性。

  • 构造函数注入(Spring 4.X推荐):

优点:

  1. 可以注入 final 修饰的属性。
  2. 通用性好,构造方法是 JDK 支持的,所以更换任何框架,它都是适用的。

缺点:注入多个对象时,构造方法会写很长。

3.5 处理一个类多个对象的注入情况:

当同一类型存在多个 bean 时,实用 @Autowired 会存在问题。

@Configuration
public class UserConfig {
    @Bean
    public UserInfo getUserInfo1(){
        return new UserInfo(1,"zhangsan");
    }
    @Bean
    public UserInfo getUserInfo2(){
        return new UserInfo(2,"lisi");
    }
}

报错如下:

image-20240930190918799

报错的原因是:非唯一的 Bean 对象。

如何解决上述问题呢?Spring提供了以下几种解决方案:

  • @Primary

  • @Qualifier

  • @Resource

3.5.1 @Primary:

使用 @Primary 注解:当存在多个相同类型的 Bean 注入时,加上 @Primary 注解,来确定默认的实现。

@Configuration
public class UserConfig {
    @Primary
    @Bean
    public UserInfo getUserInfo1(){
        return new UserInfo(1,"zhangsan");
    }
    @Bean
    public UserInfo getUserInfo2(){
        return new UserInfo(2,"lisi");
    }
}

3.5.2 @Qualifier:

使用 @Qualifier 注解:指定当前要注入的 bean 。在 @Qualifier 的 value 属性中,指定注入 bean 的名称。

注意:@Qualifier 注解不能单独使用,必须配合 @Autowired 使用。

@Controller // 将对象存储到 Spring 中
public class UserController {


    @Qualifier("getUserInfo2")
    @Autowired
    private UserInfo userInfo;

    public void printUserInfo(){
        System.out.println(userInfo);
    }
}

3.5.3 @Resource:

使用 @Resource 注解:是按照 bean 的名称进行注入。通过 name 属性指定要注入的 bean 的名称。

@Controller // 将对象存储到 Spring 中
public class UserController {
    
    @Resource(name = "getUserInfo1")
    private UserInfo userInfo;

    public void printUserInfo(){
        System.out.println(userInfo);
    }
}

常见面试题:@Autowird 与 @Resource 的区别:

  1. @Autowired 是 spring 框架提供的注解,而 @Resource 是 JDK 提供的注解。
  2. @Autowired 默认是按照类型注入,而 @Resource 是按照名称注入。相比于 @Autowired 来说,@Resource 支持更多的参数设置。

使用习惯:

如果一个类的 Bean 只有一个的话,使用 @Autowired。

如果一个类的 Bean 有多个的话,使用 @Resource。

结语:
其实写博客不仅仅是为了教大家,同时这也有利于我巩固知识点,和做一个学习的总结,由于作者水平有限,对文章有任何问题还请指出,非常感谢。如果大家有所收获的话,还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。

在这里插入图片描述

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

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

相关文章

MySQL高阶2010-职员招聘人数2

目录 题目 准备数据 分析数据 总结 题目 一家公司想雇佣新员工。公司的工资预算是 $70000 。公司的招聘标准是&#xff1a; 继续雇佣薪水最低的高级职员&#xff0c;直到你不能再雇佣更多的高级职员。用剩下的预算雇佣薪水最低的初级职员。继续以最低的工资雇佣初级职员&…

linux文件编程_进程

1. 进程相关概念 面试中关于进程&#xff0c;应该会问的的几个问题&#xff1a; 1.1. 什么是程序&#xff0c;什么是进程&#xff0c;有什么区别&#xff1f; 程序是静态的概念&#xff0c;比如&#xff1a; 磁盘中生成的a.out文件&#xff0c;就叫做&#xff1a;程序进程是…

Linux常用语法

Linux常用语法 0.引言特殊路径符Linux 命令基础格式重要命令mkdir命令echo-tail命令 vi\vim编辑器的三种工作模式vi/vim简单介绍基础命令 运行模式命令模式下的快捷键 进程管理进程的命令 Linux解压缩tar格式zip命令unzip命令 ping,wget,curl等命令的使用Linux端口端口端口的划…

【算法篇】回溯算法类(1)(笔记)

目录 一、理论基础 1. 相关题目 2. 遍历过程 3. 代码框架 二、LeetCode 题目 1. 组合 2. 组合总和III 3. 电话号码的字母组合 4. 组合总和 5. 组合总和II 6. 分割回文串 7. 复原IP地址 8. 子集 一、理论基础 1. 相关题目 2. 遍历过程 3. 代码框架 void backtr…

光通信——APON/EPON/GPON/10G PON

目录 APON EPON GPON 上下行对称和非对称速率 OAM功能 汇聚子层 ATM封装方式 GEM封装方式 10G EPON EPON/GPON技术原理和特点 工作原理 关键技术 &#xff08;1&#xff09;测距、同步 &#xff08;2&#xff09;突发发送和接收 &#xff08;3&#xff09…

基于Word2Vec和LSTM实现微博评论情感分析

关于深度实战社区 我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 社区特色…

【mmengine】优化器封装(OptimWrapper)(入门)优化器封装 vs 优化器

MMEngine 实现了优化器封装&#xff0c;为用户提供了统一的优化器访问接口。优化器封装支持不同的训练策略&#xff0c;包括混合精度训练、梯度累加和梯度截断。用户可以根据需求选择合适的训练策略。优化器封装还定义了一套标准的参数更新流程&#xff0c;用户可以基于这一套流…

SWAP、AquaCrop、FVCOM、Delft3D、SWAT、R+VIC、HSPF、HEC-HMS......

全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型&#xff0c;它综合考虑了土壤-水分-大气以及植被间的相互作用&#xff1b;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程&…

2024最新软件测试八股文(含答案+文档)

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、软件测试基础面试题 1、阐述软件生命周期都有哪些阶段? 常见的软件生命周期模型有哪些? 软件生命周期是指一个计算机软件从功能确定设计&#xff0c;到…

系统安全 - Linux 安全模型及实践

文章目录 导图Linux 安全模型用户层权限管理的细节多用户环境中的权限管理文件权限与目录权限 最小权限原则的应用Linux 系统中的认证、授权和审计机制认证机制授权机制审计机制 主机入侵检测系统&#xff08;HIDS&#xff09;_ Host-based Intrusion Detection SystemHIDS 的概…

Android问题笔记五十:构建错误-AAPT2 aapt2-7.0.2-7396180-windows Daemon

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

jmeter中token测试

案例&#xff1a; 网站&#xff1a;http://shop.duoceshi.com 讲解&#xff1a;用三个接口来讲解 第一个接口code&#xff1a;GET http://manage.duoceshi.com/auth/code 第二个登录接口&#xff1a;http://manage.duoceshi.com/auth/login 第三个接口&#xff1a;http://…

iOS中的链表 - 双向链表

iOS中的链表 - 单向链表_ios 链表怎么实现-CSDN博客​​​​​​​ 引言 在数据结构中&#xff0c;链表是一种常见的且灵活的线性存储方式。与数组不同&#xff0c;链表的元素在内存中不必连续存储&#xff0c;这使得它们在动态内存分配时更加高效。其中&#xff0c;双向链表…

Pikachu-Cross-Site Scripting-DOM型xss_x

查看代码&#xff0c;输入的内容&#xff0c;通过get请求方式&#xff0c;用text 参数带过去&#xff1b; 获取text内容&#xff0c;赋值给xss 然后拼接到 dom 里&#xff1b;构造payload的关键语句&#xff1a; <a href"xss">就让往事都随风,都随风吧</a&…

【SQL】DDL语句

文章目录 1.SQL通用语法2.SQL的分类3.DDL3.1数据库操作3.2 表操作3.2.1 表操作--数据类型3.2.2 表操作--修改3.2.3 表操作--删除 SQL 全称 Structured Query Language&#xff0c;结构化查询语言。操作关系型数据库的编程语言&#xff0c;定义了一套操作关系型数据库统一标准 。…

【Python语言初识(六)】

一、网络编程入门 1.1、TCP/IP模型 实现网络通信的基础是网络通信协议&#xff0c;这些协议通常是由互联网工程任务组 &#xff08;IETF&#xff09;制定的。所谓“协议”就是通信计算机双方必须共同遵从的一组约定&#xff0c;例如怎样建立连接、怎样互相识别等&#xff0c;…

解决MySQL报Incorrect datetime value错误

目录 一、前言二、问题分析三、解决方法 一、前言 欢迎大家来到权权的博客~欢迎大家对我的博客进行指导&#xff0c;有什么不对的地方&#xff0c;我会及时改进哦~ 博客主页链接点这里–>&#xff1a;权权的博客主页链接 二、问题分析 这个错误通常出现在尝试将一个不…

基于C++和Python的进程线程CPU使用率监控工具

文章目录 0. 概述1. 数据可视化示例2. 设计思路2.1 系统架构2.2 设计优势 3. 流程图3.1 C录制程序3.2 Python解析脚本 4. 数据结构说明4.1 CpuUsageData 结构体 5. C录制代码解析5.1 主要模块5.2 关键函数5.2.1 CpuUsageMonitor::Run()5.2.2 CpuUsageMonitor::ComputeCpuUsage(…

Python库matplotlib之五

Python库matplotlib之五 小部件(widget)RangeSlider构造器APIs应用实列 TextBox构造器APIs应用实列 小部件(widget) 小部件(widget)可与任何GUI后端一起工作。所有这些小部件都要求预定义一个Axes实例&#xff0c;并将其作为第一个参数传递。 Matplotlib不会试图布局这些小部件…

【数学分析笔记】第4章第1节 微分和导数(1)

4. 微分 4.1 微分和导数 考虑一个函数 y f ( x ) yf(x) yf(x)&#xff0c;当 x x x做一些微小的变动&#xff0c;函数值也会有微小的变动&#xff0c;比如&#xff1a; x → x △ x x\to x\bigtriangleup x x→x△x&#xff0c;则 f ( x ) → f ( x △ x ) f(x)\to f(x\bi…