IOC/DI注解开发

news2024/9/29 19:28:35

IOC/DI(Inversion of Control/Dependency Injection)是一种依赖注入的软件设计模式,它的核心思想是将对象的创建和依赖关系的管理从代码中抽离出来,交给外部容器来管理。这种设计模式可以提高代码的可维护性、可测试性和可扩展性。

在IOC/DI中,控制权被反转,即对象不再自己创建和管理它所依赖的对象,而是由外部容器来创建和管理它们。容器会根据配置文件或者注解的方式来定义对象之间的依赖关系,然后将所需的依赖对象注入到目标对象中。

通过IOC/DI,我们可以减少代码的耦合度,提高代码的可读性和可理解性。同时,依赖注入也可以帮助我们更方便地进行单元测试,因为我们可以轻松地替换掉某个依赖对象,以便进行测试。

本文将介绍IOC/DI的基本概念和原理,并演示如何使用注解来进行IOC/DI开发。在注解开发中,我们可以通过在类或者方法上添加特定的注解来定义依赖关系和配置信息,使得代码更加简洁和易于维护。

希望通过本文的介绍,读者能够了解IOC/DI的概念和优势,并掌握如何使用注解进行IOC/DI开发

文章目录

  • 一.IOC/DI注解开发
    • 1.环境准备
    • 2 注解开发定义bean
      • 步骤1:删除原XML配置
      • 步骤2:Dao上添加注解
      • 步骤3:配置Spring的注解包扫描
      • 步骤4:Service上添加注解
      • 步骤5:运行程序
        • 知识点1:@Component等
    • 3 纯注解开发模式
      • 3.1 思路分析
      • 3.2 实现步骤
        • 步骤1:创建配置类
        • 步骤2:标识该类为配置类
        • 步骤3:用注解替换包扫描配置
        • 步骤4:创建运行类并执行
        • 知识点1:@Configuration
        • 知识点2:@ComponentScan
    • 4 注解开发bean作用范围与生命周期管理
      • 4.1 环境准备
      • 4.2 Bean的作用范围
          • 知识点1:@Scope
      • 4.3 Bean的生命周期
          • 知识点1:@PostConstruct
          • 知识点2:@PreDestroy
    • 5 注解开发依赖注入
      • 5.1 环境准备
      • 5.2 注解实现按照类型注入
      • 5.3 注解实现按照名称注入
      • 5.4 简单数据类型注入
      • 5.5 注解读取properties配置文件
          • 步骤1:resource下准备properties文件
          • 步骤2: 使用注解加载properties配置文件
          • 步骤3:使用@Value读取配置文件中的内容
        • 知识点1:@Autowired
        • 知识点2:@Qualifier
        • 知识点3:@Value
        • 知识点4:@PropertySource

一.IOC/DI注解开发

Spring的IOC/DI对应的配置开发使用起来相对来说还是比较复杂的,复杂的地方在配置文件。

Spring可以简化代码的开发,到现在并没有体会到。

所以Spring到底是如何简化代码开发的呢?

要想真正简化开发,就需要用到Spring的注解开发,Spring对注解支持的版本历程:

  • 2.0版开始支持注解
  • 2.5版注解功能趋于完善
  • 3.0版支持纯注解开发

关于注解开发,有两块内容注解开发定义bean纯注解开发

注解开发定义bean用的是2.5版提供的注解,纯注解开发用的是3.0版提供的注解。

1.环境准备

在学习注解开发之前,先来准备下案例环境:

  • 创建一个Maven项目
  • pom.xml添加Spring的依赖
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>

        <artifactId>spring-context</artifactId>

        <version>5.2.10.RELEASE</version>

    </dependency>

</dependencies>
  • resources下添加applicationContext.xml
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="bookDao" class="com.leon.dao.impl.BookDaoImpl"/>
</beans>
  • 添加BookDao、BookDaoImpl、BookService、BookServiceImpl类
public interface BookDao {
    public void save();
}
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ..." );
    }
}
public interface BookService {
    public void save();
}

public class BookServiceImpl implements BookService {
    public void save() {
        System.out.println("book service save ...");
    }
}
  • 创建运行类App
public class App {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
    }
}

2 注解开发定义bean

在上述环境的基础上,我们来学一学Spring是如何通过注解实现bean的定义开发?

步骤1:删除原XML配置

将配置文件中的<bean>标签删除掉

<bean id="bookDao" class="com.leon.dao.impl.BookDaoImpl"/>

步骤2:Dao上添加注解

在BookDaoImpl类上添加@Component注解

@Component("bookDao")
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ..." );
    }
}

注意:@Component注解不可以添加在接口上,因为接口是无法创建对象的。

XML与注解配置的对应关系:

img

步骤3:配置Spring的注解包扫描

为了让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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <context:component-scan base-package="com.leon"/>
</beans>

说明:

component-scan

  • component:组件,Spring将管理的bean视作自己的一个组件
  • scan:扫描

base-package指定Spring框架扫描的包路径,它会扫描指定包及其子包中的所有类上的注解。

  • 包路径越多[如:com.leon.dao.impl],扫描的范围越小速度越快
  • 包路径越少[如:com.leon],扫描的范围越大速度越慢
  • 一般扫描到项目的组织名称即Maven的groupId下[如:com.leon]即可。

步骤4:Service上添加注解

在BookServiceImpl类上也添加@Component交给Spring框架管理

@Component
public class BookServiceImpl implements BookService {
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

步骤5:运行程序

在App类中,从IOC容器中获取BookServiceImpl对应的bean对象,打印

public class App {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        System.out.println(bookDao);
        //按类型获取bean
        BookService bookService = ctx.getBean(BookService.class);
        System.out.println(bookService);
    }
}

打印观察结果,两个bean对象都已经打印到控制台

说明:

  • BookServiceImpl类没有起名称,所以在App中是按照类型来获取bean对象
  • @Component注解如果不起名称,会有一个默认值就是当前类名首字母小写,所以也可以按照名称获取,如
BookService bookService = (BookService)ctx.getBean("bookServiceImpl");
System.out.println(bookService);

对于@Component注解,还衍生出了其他三个注解@Controller@Service@Repository

通过查看源码会发现:

img

这三个注解和@Component注解的作用是一样的,为什么要衍生出这三个呢?

方便我们后期在编写类的时候能很好的区分出这个类是属于表现层业务层还是数据层的类。

知识点1:@Component等
名称@Component/@Controller/@Service/@Repository
类型类注解
位置类定义上方
作用设置该类为spring管理的bean
属性value(默认):定义bean的id

3 纯注解开发模式

上面已经可以使用注解来配置bean,但是依然有用到配置文件,在配置文件中对包进行了扫描,Spring在3.0版已经支持纯注解开发

  • Spring3.0开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道

具体如何实现?

3.1 思路分析

实现思路为:

  • 将配置文件applicationContext.xml删除掉,使用类来替换。

3.2 实现步骤

步骤1:创建配置类

创建一个配置类SpringConfig

public class SpringConfig {
}
步骤2:标识该类为配置类

在配置类上添加@Configuration注解,将其标识为一个配置类,替换applicationContext.xml

@Configuration
public class SpringConfig {
}
步骤3:用注解替换包扫描配置

在配置类上添加包扫描注解@ComponentScan替换<context:component-scan base-package=""/>

@Configuration
@ComponentScan("com.leon")
public class SpringConfig {
}
步骤4:创建运行类并执行

创建一个新的运行类AppForAnnotation

public class AppForAnnotation {

    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        System.out.println(bookDao);
        BookService bookService = ctx.getBean(BookService.class);
        System.out.println(bookService);
    }
}

运行AppForAnnotation,可以看到两个对象依然被获取成功

至此,纯注解开发的方式就已经完成了,主要内容包括:

  • Java类替换Spring核心配置文件
    img
  • @Configuration注解用于设定当前类为配置类
  • @ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
@ComponentScan({com.leon.service","com.leon.dao"})
  • 读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象
//加载配置文件初始化容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//加载配置类初始化容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
知识点1:@Configuration
名称@Configuration
类型类注解
位置类定义上方
作用设置该类为spring配置类
属性value(默认):定义bean的id
知识点2:@ComponentScan
名称@ComponentScan
类型类注解
位置类定义上方
作用设置spring配置类扫描路径,用于加载使用注解格式定义的bean
属性value(默认):扫描路径,此路径可以逐层向下扫描

小结:

这一节重点掌握的是使用注解完成Spring的bean管理,需要掌握的内容为:

  • 记住@Component、@Controller、@Service、@Repository这四个注解
  • applicationContext.xml中<context:component-san/>的作用是指定扫描包路径,注解为@ComponentScan
  • @Configuration标识该类为配置类,使用类替换applicationContext.xml文件
  • ClassPathXmlApplicationContext是加载XML配置文件
  • AnnotationConfigApplicationContext是加载配置类

4 注解开发bean作用范围与生命周期管理

使用注解已经完成了bean的管理,接下来按照前面所学习的内容,将通过配置实现的内容都换成对应的注解实现,包含两部分内容:bean作用范围bean生命周期

4.1 环境准备

  • 创建一个Maven项目
  • pom.xml添加Spring的依赖
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>

        <artifactId>spring-context</artifactId>

        <version>5.2.10.RELEASE</version>

    </dependency>

</dependencies>
  • 添加一个配置类SpringConfig
@Configuration
@ComponentScan("com.leon")
public class SpringConfig {
}
  • 添加BookDao、BookDaoImpl类
public interface BookDao {
    public void save();
}
@Repository
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ..." );
    }
}
  • 创建运行类App
public class App {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao1 = ctx.getBean(BookDao.class);
        BookDao bookDao2 = ctx.getBean(BookDao.class);
        System.out.println(bookDao1);
        System.out.println(bookDao2);
    }
}

最终创建好的项目结构如下:

4.2 Bean的作用范围

(1)先运行App类,在控制台打印两个一摸一样的地址,说明默认情况下bean是单例

(2)要想将BookDaoImpl变成非单例,只需要在其类上添加@scope注解

@Repository
//@Scope设置bean的作用范围
@Scope("prototype")
public class BookDaoImpl implements BookDao {

    public void save() {
        System.out.println("book dao save ...");
    }
}

再次执行App类,打印结果显示已经不是一个对象

知识点1:@Scope
名称@Scope
类型类注解
位置类定义上方
作用设置该类创建对象的作用范围 可用于设置创建出的bean是否为单例对象
属性value(默认):定义bean作用范围, 默认值singleton(单例),可选值prototype(非单例)

4.3 Bean的生命周期

(1)在BookDaoImpl中添加两个方法,initdestroy,方法名可以任意

@Repository
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
    public void init() {
        System.out.println("init ...");
    }
    public void destroy() {
        System.out.println("destroy ...");
    }
}

(2)如何对方法进行标识,哪个是初始化方法,哪个是销毁方法?

只需要在对应的方法上添加@PostConstruct@PreDestroy注解即可。

@Repository
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
    @PostConstruct //在构造方法之后执行,替换 init-method
    public void init() {
        System.out.println("init ...");
    }
    @PreDestroy //在销毁方法之前执行,替换 destroy-method
    public void destroy() {
        System.out.println("destroy ...");
    }
}

(3)要想看到两个方法执行,需要注意的是destroy只有在容器关闭的时候,才会执行,所以需要修改App的类

public class App {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao1 = ctx.getBean(BookDao.class);
        BookDao bookDao2 = ctx.getBean(BookDao.class);
        System.out.println(bookDao1);
        System.out.println(bookDao2);
        ctx.close(); //关闭容器
    }
}

(4)运行App,类查看打印结果,证明init和destroy方法都被执行了。

注意:@PostConstruct和@PreDestroy注解如果找不到,需要导入下面的jar包

<dependency>
  <groupId>javax.annotation</groupId>
  <artifactId>javax.annotation-api</artifactId>
  <version>1.3.2</version>
</dependency>

找不到的原因是,从JDK9以后jdk中的javax.annotation包被移除了,这两个注解刚好就在这个包中。

知识点1:@PostConstruct
名称@PostConstruct
类型方法注解
位置方法上
作用设置该方法为初始化方法
属性
知识点2:@PreDestroy
名称@PreDestroy
类型方法注解
位置方法上
作用设置该方法为销毁方法
属性

小结

img

5 注解开发依赖注入

Spring为了使用注解简化开发,并没有提供构造函数注入setter注入对应的注解,只提供了自动装配的注解实现。

5.1 环境准备

在学习之前,把案例环境介绍下:

  • 创建一个Maven项目
  • pom.xml添加Spring的依赖
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>

        <artifactId>spring-context</artifactId>

        <version>5.2.10.RELEASE</version>

    </dependency>

</dependencies>
  • 添加一个配置类SpringConfig
@Configuration
@ComponentScan("com.leon")
public class SpringConfig {
}
  • 添加BookDao、BookDaoImpl、BookService、BookServiceImpl类
public interface BookDao {
    public void save();
}
@Repository
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ..." );
    }
}
public interface BookService {
    public void save();
}
@Service
public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}
  • 创建运行类App
public class App {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookService bookService = ctx.getBean(BookService.class);
        bookService.save();
    }
}

环境准备好后,运行后会发现有问题

出现问题的原因是,在BookServiceImpl类中添加了BookDao的属性,并提供了setter方法,但是目前是没有提供配置注入BookDao的,所以bookDao对象为Null,调用其save方法就会报控指针异常

5.2 注解实现按照类型注入

对于这个问题使用注解该如何解决?

(1) 在BookServiceImpl类的bookDao属性上添加@Autowired注解

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    private BookDao bookDao;
    
//	  public void setBookDao(BookDao bookDao) {
//        this.bookDao = bookDao;
//    }
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

注意:

  • @Autowired可以写在属性上,也可也写在setter方法上,最简单的处理方式是写在属性上并将setter方法删除掉

  • 为什么setter方法可以删除呢?

  • 自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值

  • 普通反射只能获取public修饰的内容

  • 暴力反射除了获取public修饰的内容还可以获取private修改的内容

  • 所以此处无需提供setter方法

(2)@Autowired是按照类型注入,那么对应BookDao接口如果有多个实现类,比如添加BookDaoImpl2

@Repository
public class BookDaoImpl2 implements BookDao {
    public void save() {
        System.out.println("book dao save ...2");
    }
}

这个时候再次运行App,就会报错

此时,按照类型注入就无法区分到底注入哪个对象,解决方案:按照名称注入

  • 先给两个Dao类分别起个名称
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ..." );
    }
}
@Repository("bookDao2")
public class BookDaoImpl2 implements BookDao {
    public void save() {
        System.out.println("book dao save ...2" );
    }
}

此时就可以注入成功,但是得思考个问题:

  • @Autowired是按照类型注入的,给BookDao的两个实现起了名称,它还是有两个bean对象,为什么不报错?

  • @Autowired默认按照类型自动装配,如果IOC容器中同类的Bean找到多个,就按照变量名和Bean的名称匹配。因为变量名叫bookDao而容器中也有一个booDao,所以可以成功注入。

  • 分析下面这种情况是否能完成注入呢?

  • img

  • 不行,因为按照类型会找到多个bean对象,此时会按照bookDao名称去找,因为IOC容器只有名称叫bookDao1bookDao2,所以找不到,会报NoUniqueBeanDefinitionException

5.3 注解实现按照名称注入

当根据类型在容器中找到多个bean,注入参数的属性名又和容器中bean的名称不一致,这个时候该如何解决,就需要使用到@Qualifier来指定注入哪个名称的bean对象。

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    @Qualifier("bookDao1")
    private BookDao bookDao;
    
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

@Qualifier注解后的值就是需要注入的bean的名称。

注意:@Qualifier不能独立使用,必须和@Autowired一起使用

5.4 简单数据类型注入

引用类型看完,简单类型注入就比较容易懂了。简单类型注入的是基本数据类型或者字符串类型,下面在BookDaoImpl类中添加一个name属性,用其进行简单类型注入

@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    private String name;
    public void save() {
        System.out.println("book dao save ..." + name);
    }
}

数据类型换了,对应的注解也要跟着换,这次使用@Value注解,将值写入注解的参数中就行了

@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    @Value("leon")
    private String name;
    public void save() {
        System.out.println("book dao save ..." + name);
    }
}

注意数据格式要匹配,如将"abc"注入给int值,这样程序就会报错。

介绍完后,会有一种感觉就是这个注解好像没什么用,跟直接赋值是一个效果,还没有直接赋值简单,所以这个注解存在的意义是什么?

5.5 注解读取properties配置文件

@Value一般会被用在从properties配置文件中读取内容进行使用,具体如何实现?

步骤1:resource下准备properties文件

jdbc.properties

name=leon888
步骤2: 使用注解加载properties配置文件

在配置类上添加@PropertySource注解

@Configuration
@ComponentScan("com.leon")
@PropertySource("jdbc.properties")
public class SpringConfig {
}
步骤3:使用@Value读取配置文件中的内容
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    @Value("${name}")
    private String name;
    public void save() {
        System.out.println("book dao save ..." + name);
    }
}

步骤4:运行程序

运行App类,查看运行结果,说明配置文件中的内容已经被加载到

注意:

  • 如果读取的properties配置文件有多个,可以使用@PropertySource的属性来指定多个
@PropertySource({"jdbc.properties","xxx.properties"})
  • @PropertySource注解属性中不支持使用通配符*,运行会报错
@PropertySource({"*.properties"})
  • @PropertySource注解属性中可以把classpath:加上,代表从当前项目的根路径找文件
@PropertySource({"classpath:jdbc.properties"})
知识点1:@Autowired
名称@Autowired
类型属性注解 或 方法注解(了解) 或 方法形参注解(了解)
位置属性定义上方 或 标准set方法上方 或 类set方法上方 或 方法形参前面
作用为引用类型属性设置值
属性required:true/false,定义该属性是否允许为null
知识点2:@Qualifier
名称@Qualifier
类型属性注解 或 方法注解(了解)
位置属性定义上方 或 标准set方法上方 或 类set方法上方
作用为引用类型属性指定注入的beanId
属性value(默认):设置注入的beanId
知识点3:@Value
名称@Value
类型属性注解 或 方法注解(了解)
位置属性定义上方 或 标准set方法上方 或 类set方法上方
作用为 基本数据类型 或 字符串类型 属性设置值
属性value(默认):要注入的属性值
知识点4:@PropertySource
名称@PropertySource
类型类注解
位置类定义上方
作用加载properties文件中的属性值
属性value(默认):设置加载的properties文件对应的文件名或文件名组成的数组

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

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

相关文章

【包教包会】怎么购买海外域名?Namecheap+虚拟卡购买步骤详解

前言 为什么要用海外域名&#xff1f; 首先&#xff0c;胖虎要介绍一下为什么要使用海外域名&#xff0c;使用国内的域名不好吗&#xff1f;主要是出于以下几个原因供大家参考&#xff0c;主要是涵盖了品牌保护、市场拓展、灵活性和创新性等多个方面&#xff1a; 品牌保护&a…

油耳朵用什么耳勺?揭露行业的五大隐患套路!

油耳清洁是很多人的一个困惑&#xff0c;由于外耳道分泌油性耵聍过多而导致。油耳使用传统耳勺和棉签很容易掏不干净&#xff0c;而可视挖耳勺采用了柔软且耐用的材料制成&#xff0c;可以避免因材料过硬对耳道造成损伤。并且用户可以通过摄像头清晰地看到耳道内的情况&#xf…

Java导出DBF文件(附带工具类)

导出DBF文件 先看效果 JavaDBF 使用JavaDBF库 数据类型映射 写入支持的类型 类型XBase类型XBase 符号JavaDBF 中使用的 Java 类型字符CharacterCjava.lang.String数值NumericNjava.math.BigDecimal浮点Floating PointFjava.math.BigDecimal布尔LogicalLjava.lang.Boolea…

公司如何监控员工电脑,怎么监控电脑进程

在现代企业管理中&#xff0c;监控员工电脑的行为已成为确保工作效率、数据安全和合规性的重要措施。通过合理的监控手段&#xff0c;企业可以预防潜在的安全威胁&#xff0c;优化工作流程&#xff0c;并确保员工遵循公司的政策和规定。 公司监控员工电脑的常见方法 屏幕监控&…

什么是pk答题软件源码

答题软件的源码是开发答题软件的基础程序代码。由于答题软件的功能和复杂程度不同&#xff0c;其源码也会有很大差异。 一般来说&#xff0c;答题软件的源码可能包含以下几个主要部分&#xff1a; 一、用户界面部分 登录和注册界面&#xff1a; 允许用户输入用户名、密码等信…

C++资料电子书资源PDF免费分享

C电子书 这里写目录标题 C电子书目录资源获取 目录 《数据结构(C语言版)》(严蔚敏 吴伟明编著).pdf 7.6MB 《C程序设计题解与上机指导》(第二版).谭浩强.pdf 7.0MB 《C程序设计(第四版)学习辅导》.谭浩强.扫描版.pdf 13.1MB 《C程序设计》第一版&#xff08;谭浩强&#xff09…

个人笔记--python画图(一维,二维,三维)

1. 一维 1. plot import numpy as np import matplotlib.pyplot as plt# linspace(): 创建等间距的数值序列 x np.linspace(0, 2 * np.pi, 100)u np.sin(x)# 绘制一维图形 plt.figure() plt.plot(x, u) plt.title(Plot of sin(x)) plt.xlabel(x) plt.ylabel(sin(x)) plt.sh…

监控摄像头能看到电脑屏幕吗?公司监控摄像头拍员工电脑屏幕!

监控摄像头已经成为许多企业和公共场所不可或缺的安全管理工具。 它们不仅守护着物理空间的安全&#xff0c;也在一定程度上影响着企业的运营管理和员工的行为规范。 然而&#xff0c;当“公司监控摄像头拍员工电脑屏幕”这一话题被提出时&#xff0c;不禁引发了广泛的讨论与…

Sketch for mac(专业矢量绘图设计软件100.3版) 中文激活版 一键快速安装!

Sketch 是一款专为 macOS 设计的专业矢量图形编辑软件&#xff0c;自发布以来便成为 UI/UX 设计师首选的工具之一。其简洁高效的用户界面、强大的设计功能&#xff0c;以及与 macOS 系统的深度集成&#xff0c;使得 Sketch 在设计领域享有很高的声誉。无论是移动应用设计、网页…

PT:如何获取net的Delta delay信息

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 来自星球提问: crosstalk的Delta delay可以从三个渠道获取: report_timing

监控用户登录信息,执行事务码情况

CMOD->SUSR0001 *&---------------------------------------------------------------------* *& 包含 ZXUSRU01 *&---------------------------------------------------------------------*DATA:lv_sblm_obj TYPE sblm_obj.CALL FUNCTION ZFMB…

2-Git远程仓库

Git中存在两种类型的仓库&#xff0c;即本地仓库和远程仓库。那么我们如何搭建Git远程仓库呢&#xff1f;我们可以借助互联网上提供的一些代码托管服务来实现&#xff0c;其中比较常用的有GitHub、码云、GitLab等。 一、配置远程仓库 1.注册登录Gitee/Github GitHub 地址&am…

【ComfyUI Flux_dev_gguf】 AI绘画提示词,轻松实现AI仰角摄影技巧。秒出AI大片~

前言 **hello&#xff0c;大家好&#xff0c;我是老徐&#xff0c;热爱AI&#xff0c;一路同行&#xff0c;与你相伴~喜欢的可以关注老徐&#xff0c;**在文章底部添加老徐微信&#xff0c;加入老徐AI绘画交流群 今天老徐简单和大家分享下基于ComfyUI Flux_dev_gguf 工作流&…

CX1020 N010处理器CX1020-N010模块面价

CX1020 N010处理器CX1020-N010模块面价 CX1020 N010处理器CX1020-N010模块面价 CX1020 N010处理器CX1020-N010模块面价 CX1020-N010处理器CX1020 N010模块引脚线 CX1020-N010处理器CX1020 N010模块接线图 CX1020-N010处理器CX1020 N010模块电路图 CX1020-N010中央处理器&…

R 2火灾温度预测

火灾温度预测 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 使用LSTM进行时间序列预测 这周学习如何使用长短期记忆网络&#xff08;LSTM&#xff09;进行时间序列预测。使用PyTorch框架来构建和训练模型&…

【大数据算法】一文掌握大数据算法之:时间亚线性算法。

时间亚线性算算法 1、引言2、时间亚线性算法2.1 定义2.2 分类2.3 核心原理2.4 算法公式2.5 代码示例 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c;大数据算法知识难不难啊&#xff1f; 小鱼&#xff1a;你在职场打拼这么多年&#xff0c;竟然还能问出来这个问题。 小屌…

婚恋交友系统该如何制作成品系统?

制作婚恋交友系统的成品系统是一个综合性的过程&#xff0c;涉及多个关键步骤和技术要点。以下是一个详细的制作流程&#xff1a; 1. 需求分析 市场调研&#xff1a;首先需要对婚恋交友市场进行深入调研&#xff0c;了解目标用户群体的需求、喜好、习惯以及市场痛点。用户画像…

C学习(数据结构)--> 实现顺序结构二叉树

目录 一、堆的概念与结构 性质 二叉树的性质 二、堆的实现 1、结构 2、初始化与销毁 3、入堆与出堆&#xff08;小堆&#xff09; 1&#xff09;Swap 2&#xff09;入堆 1 数据的向上调整 2 入堆 3&#xff09;出堆 1 数据的向下调整 2 出堆 三、其他 1、入堆与出…

解决Github无法连接codespace情况

使用这个DNS即可 CN - 中国互联网络信息中心CNNIC SDNS1.2.4.8,,True 参见&#xff1a; GitHub 无法访问解决办法 - 哔哩哔哩

一些可以参考的文档集合17

应用运行主目录 之前的文章集合: 一些可以参考文章集合1_xuejianxinokok的博客-CSDN博客 一些可以参考文章集合2_xuejianxinokok的博客-CSDN博客 一些可以参考的文档集合3_xuejianxinokok的博客-CSDN博客 一些可以参考的文档集合4_xuejianxinokok的博客-CSDN博客 一些可以…