Spring入门(万字详细附代码讲解)

1.Spring介绍

Spring其实就是一种开源框架,指的是Spring Framework,具有良好的生态,这也是Spring经久不衰的原因

用一句话概括,Spring就是一个集成了众多工具和方法的IOC容器

2.IOC容器

什么是IOC容器呢?

IOC的中文翻译过来就是控制反转,IOC容器其实就是控制反转容器

那什么是控制反转呢?

这个词听起来好像很高大上,其实通俗来理解就是,本来我们写java类的时候,创建对象,是通过自己去new的,但是当我们控制反转之后,我们就把对象的创建和一系列读取等操作交给了Spring,Spring就帮我们完成这些操作 ,这样我们需要做的操作就两个,1.把对象存到Spring中去,2.从Spring中去取对象

3.控制反转(IOC)的好处

我们以一部手机为例,就简易的手机,假如我们需要的有CPU,线路板,电阻来组成

这样我们传统的代码开发,就要先new一个手机,但是我们想要完成一部手机,要有一个CPU,所以再调用CPU类组装CPU,但是CPU想要组装,就必须要先组装线路板,但是线路板想要组装,就必须依靠电阻,这样我们的程序就非常耦合,我们通过一张图,更加直观的来理解

可以看到,我们想要造一部手机,耦合度非常的高,如果我们的电阻这一栏,我们加一个电容属性,那么,我们上面的线路板中也需要把调用电阻的那一块进行修改,从而导致我们整个的代码都需要进行一个更新,这个时候,IOC的优势便体现出来了

我们只需要进行一个改进,就可以大大降低耦合度,我们可以在main函数中,将每一个对象都进行创建,然后我们可以在每一个类中,创建一个属性,用来接收下一级的对象,这样在我们进行对底层修改的时候,只需要对修改的代码进行修改和main函数中的参数进行修改即可,大大降低了带啊吗的耦合,我们也用一个图来理解

 

可以明显的看出来IOC容器的优势 

4.DI

DI是一种设计模式,就是依赖注入,在我们想要运行A时,A需要依赖数据库来完成,这时候我们不会像传统开发一样,去搭建DBUtile或者去newDBUtile的对象,而是将依赖关系配置到xml文件中去,由Spring去管理,这样就可以动态的去依赖关系注入到对象之中,从而实现解耦合

2.Spring使用

这里就不去教大家如何创建Spring项目了,我们如何使用Spring呢?,需要在xml文件中去添加Spring的依赖即可

这里我们具体讲一下如何存取对象

1.较为古老的用法

1.1添加启动类

我们需要在java包中进行创建一个启动类,只要包含main方法即可,类似这样

public class App {
    public static void main(String[] args) {
        
    }
}

1.2创建Bean

什么是Bean呢?

Bean对象就是java中的普通对象,这里其实本质是一个类的写法

类似下面

public class User {
    public String Hi(String s){
        return "Hi " + s;
    }
}

1.3存储Bean

创建好Bean之后,我们需要将其注册到Spring中去

这里我们使用最原始的方法

首先创建一个xml文件,在resource目录下,如下

这里面先将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">
    <beans>
        <bean id = "user" class="com.ganzhi.User"></bean>
    </beans>
</beans>

 然后我们只需要将User对象注入到Spring中即可

1.4获取Bean

我们创建Bean的目的就是为了拿来用,那我们要如何取到Bean中的属性呢

首先我们需要得到Spring的上下文对象

因为我们的Bean是交给Spring来管理的,所以需要用一个Spring 的上下文来进行操作,可以用如下的代码来实现

public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring-config.xml");
    }
}

不仅如此,我们还可以利用Bean Factory来作为Spring的上下文,代码如下

public class App {
    public static void main(String[] args) {
//        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring-config.xml");
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("Spring-config.xml"));
    }
}

这里BeanFactory其实和上面的ApplicationContext效果是一样的,后者是前者的子类

常见面试题:

BeanFactory 和 ApplicationContext的区别

1.二者都是Spring的顶级容器,并且ApplicationContext是BeanFactory的子类,他除了继承了BeanFactory的所有功能外,还增加了国际化支持,资源访问支持,事件传播等方面的支持

2.从性能方面,ApplicationContext属于饿汉加载(也就是一次性加载并且初始化所有的Bean对象)而BeanFactory是懒汉加载(用到哪个Bean对象就加载哪个),所以我们可以看出来,BeanFactory比ApplicationContext更加轻量

拓展:这里还有个ClassPathXmlApplicationContext类,他是Application的子类

1.5获取指定的Bean对象

这里可以通过这种方法来获取Bean对象

public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring-config.xml");
//        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("Spring-config.xml"));

        User user = (User) applicationContext.getBean("user");
        System.out.println(user.Hi("张三"));
    }
}

注意:这里getBean中的"user"必须和xml中的Beanid保存一致

 

了解getBean()的重载方法

public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring-config.xml");
//        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("Spring-config.xml"));

        User user = (User) applicationContext.getBean(User.class);
        System.out.println(user.Hi("张三"));
    }
}

 这里也可以直接用类名来获取

或者id和类名一起使用

package com.ganzhi;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 
 * Date: 2023-04-05
 * Time: 17:55
 */
public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring-config.xml");
//        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("Spring-config.xml"));

        User user = (User) applicationContext.getBean("user",User.class);
        System.out.println(user.Hi("张三"));
    }
}

这里用一张图,带大家了解一下具体的流程

2.现在的 方法

1.配置扫描路径

这里我们需要告诉Spring去哪里扫描类,并存储,所以是非常重要的步骤

这里我们附上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"
       xmlns:content="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <content:component-scan base-package="com.ganzhi"></content:component-scan>
</beans>

 其中的content一行就是我们要扫描的路径

2.添加类注解

2.1@Controller(控制器存储)

我们使用可以用@Controller来让对象存入到Spring,代码示例如下

@Controller
public class User {
    public String Hi(String s){
        return "Hi " + s;
    }
}

这样我们就可以扫描到这个对象了,利用上述的App类中的main,依然可以执行

代码再次附上

package com.ganzhi;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 
 * Date: 2023-04-05
 * Time: 17:55
 */
public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring-config.xml");
//        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("Spring-config.xml"));

        User user = (User) applicationContext.getBean("user");
        System.out.println(user.Hi("张三"));
    }
}

2.2.@Service(服务存储)

代码如下

@Service
public class User {
    public String Hi(String s){
        return "Hi " + s;
    }
}

2.3.@Repository(仓库存储)

代码如下

@Repository
public class User {
    public String Hi(String s){
        return "Hi " + s;
    }
}

其他两个是@Component(组件存储) 和@Configuration(配置存储)使用方法都是和上面一样得到

4.类注解类型多的原因

既然我们的类注解好像功能都是一样的,那为什么我们还要分那么多类型呢?

其实还是为了区分不同注解的用途,但是都能用,这里就显示出我们Spring的宗旨了(约定大于配置)

@Controller是表示的是业务逻辑层,用于检查参数的有效性

@Service是服务层,调用持久化类实现的一些功能

@Repository是持久层的,也就是持久存储数据的,直接和数据库进行交互

@Configuration是配置层的,用于配置当前项目的一些信息

@Component是归属于公共工具类

不同的注解,调用流程是不同的,是Controller->Service->Repository

而Component是他们四个的父类

5.Bean的命名规则

5.51.类名的首字母大写,第二个字母小写

这种就是我们一般类的命名规则,这里我们直接小写首字母即可完成读取

这种也是我们最常见的

5.2.第一个和第二个字母都是大写

这里需要用原类名来读取

 5.3.源码概读

这里我们可以直接去源码查找命名规则

这里我们直接唤醒idea的搜索,去搜索beanName,可以找到下面这个类

 然后直接点进去,找到下面的方法

 很明显,这里返回值里面调用的方法就是我们想要找的命名规则

之间按住ctrl点击这个方法,去进行查看,就会得到下面的方法

 从这个方法我们

可以看到,如果我们传入的名字是null或者长度为0,他会直接返回,如果不是,那下面第一个if语句的语义就是,如果第一个字母和第二个字母都是大写的话,就直接返回名字,如果不是,则走下面的,也就是其他情况,那么我们的做法就是第一个字母小写

从这里也可以推导出,如果第一个字母小写,那么我们获取类的时候也需要第一个字母小写,也就是不需要更改

6.方法注解@Bean

方法注解就是放到某些方法上面的注解,但是需要注意,方法注解要配合类注解一起使用才有效

而且Bean注解有多种用法,这是第一种,也是最简单的一种

类似下面 

6.1Bean常规的使用

有一个User类,里面存放User对象

package com;

import org.springframework.stereotype.Controller;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * com.User: 
 * Date: 2023-04-05
 * Time: 17:59
 */
@Controller
public class User {
    private int Id;
    private String Name;

    public int getId() {
        return Id;
    }

    public void setId(int id) {
        Id = id;
    }

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "Id=" + Id +
                ", Name='" + Name + '\'' +
                '}';
    }
}

                                                                                                                                                                                     

然后我们弄一个Users来存放User对象,顺便使用并@Bean注解

package com.ganzhi;

import com.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User:  
 * Date: 2023-04-06
 * Time: 21:17
 */
@Controller
public class Users {
    @Bean
    public User getUser(){
        User user = new User();
        user.setId(1);
        user.setName("zhangsan");
        return user;
    }
}

     随后我们在App类中去运行                                                                                                                 

package com;

import com.ganzhi.UserController;
import com.ganzhi.UserTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * com.User:  
 * Date: 2023-04-05
 * Time: 17:55
 */
public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring-config.xml");


        User user = (User) applicationContext.getBean("getUser");
        System.out.println(user);
    }
}

                          注意:这里的Bean命名规则和上面的命名规则是一致的,运行效果如下

注意:!!!!这里被Bean存入和获取的是不可以有参数的方法,因为这种方法存取参数是无法进行传递的

              证明了我们,可以正常去获得到Bean

 6.2.这里我们还可以重命名Bean

如下

package com.ganzhi;

import com.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User:  
 * Date: 2023-04-06
 * Time: 21:17
 */
@Controller
public class Users {
    @Bean(name = {"u1"})
    public User getUser(){
        User user = new User();
        user.setId(1);
        user.setName("zhangsan");
        return user;
    }
}
package com;

import com.ganzhi.UserController;
import com.ganzhi.UserTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * com.User:  
 * Date: 2023-04-05
 * Time: 17:55
 */
public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring-config.xml");


        User user = (User) applicationContext.getBean("u1");
        System.out.println(user);
    }
}

这里我们就给Bean重新起了一个叫u1的名字

注意:这里重命名的{}内其实是一个数组,可以存放多个Bean名,而且在读取的时候只要按照正确的方式,完全可以正常存取

7.对象装配

在上面我们都是通过applicationContext来拿到Bean的,那我们怎么样在非运行类中赋值给变量呢?

这里我们就会使用到对象装配,这里也叫注入,有三种方式:属性注入,set注入,构造方法注入

7.1.属性注入

这是实现起来最简单的,只需要在需要赋值的变量上面加个@Autowired即可

我们为了更好理解,就新建两个类,一个UserController,一个UserTest

UserController:

这个类是为了让我们拿到user对象,并且返回出去,便于UserTest调用

package com.ganzhi;

import com.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * com.User:  
 * Date: 2023-04-05
 * Time: 21:18
 */
@Controller
public class UserController {
    public User getUserById(Integer id){
        User user = new User();
        user.setId(id);
        user.setName("zhangsan");
        return user;
    }
}

UserTest:

这个类是把上面存入的UserController 对象取出来,并且调用里面的getUserById方法,拿到User,返回给运行类,这里使用了属性注解,将Spring中的UserController 进行装配

package com.ganzhi;

import com.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 王 
 * Date: 2023-04-06
 * Time: 21:33
 */
@Controller
public class UserTest {
   @Autowired
    private UserController userController;

    
    public User getUserById(Integer id){
        return userController.getUserById(id);
    }
}

然后我们通过App类进行执行

package com;

import com.ganzhi.UserController;
import com.ganzhi.UserTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * com.User:  
 * Date: 2023-04-05
 * Time: 17:55
 */
public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring-config.xml");
//        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("Spring-config.xml"))
        UserTest userTest = applicationContext.getBean(UserTest.class);
        System.out.println(userTest.getUser(5).toString());


    }
}

这里需要注意,我们拿到的是UserTest对象,而UserTest被注入了UserController对象,然而通过UserController的getUserById可以拿到一个User对象,再通过UserTest的getUserById返回给运行类,即可拿到User,我们这里模拟的是从库中取数据,所以反复调用,繁琐一些

执行结果如下

7.2.构造方法注入

我们这里只改变UserTest类

package com.ganzhi;

import com.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User:  
 * Date: 2023-04-06
 * Time: 21:33
 */
@Controller
public class UserTest {

    private UserController userController;
    @Autowired
    public UserTest(UserController userController){
        this.userController = userController;
    }

    public User getUser(Integer id){
        return userController.getUserById(id);
    }
}

 这里我们通过构造方法进行构造,我们 通过Autowired注解,给参数UserController进行赋值,然后通过构造方法中的赋值进行注入,也可以正确得到结果,这里就不赘述

注意:当当前类只有一个构造方法时,可以省略@Autowired

7.3.set注入

这里我们还是更改UserTest方法

package com.ganzhi;

import com.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 王久实
 * Date: 2023-04-06
 * Time: 21:33
 */
@Controller
public class UserTest {

    private UserController userController;

    @Autowired
    public void setUserController(UserController userController){
        this.userController = userController;
    }
    public User getUser(Integer id){
        return userController.getUserById(id);
    }
}

这里和上面的逻辑基本差不多,但是这里不可以省略@Autowired

7.4.三种方法比较(面试题)

重要

属性注入:

        优势:使用简单,方便

        劣势:只适用于IOC容器,只有在使用当前属性时,才会触发空指针异常

构造方法注入:

        优势:Spring官方推荐,通用,在使用之前,可以保证传入的类不为空,更符合单一设计原则

        劣势:写法比较麻烦

set注入:

        优势:基本无

        劣势:不如属性注入简介,不如构造方法通用

7.5.Resource注解关键字

我们进行类注入时,不仅可以使用Autowired还可以使用Resource,这里基本使用方法和上面一致

我们主要说一下不同的地方

1.Resource是来自于JDK的注解,而Autowired来自于Spring

2.Resource不适用于构造方法注入

3.Resource可以支持Bean设置更多参数,如name,代码如下

 Users:

package com.ganzhi;

import com.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User:  
 * Date: 2023-04-06
 * Time: 21:17
 */
@Controller
public class Users {
    @Bean
    public User getUser1(){
        User user = new User();
        user.setId(1);
        user.setName("zhangsan");
        return user;
    }
    @Bean
    public User getUser2(){
        User user = new User();
        user.setId(2);
        user.setName("lisi");
        return user;
    }
}

这里我们弄了两个Bean注解,那么我们就需要通过方法名来找了,但是Autowired却没有name参数,这时候,我们就可以使用Resource注解

UserResource:

package com.ganzhi;

import com.User;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User:   
 * Date: 2023-04-08
 * Time: 17:29
 */
@Controller
public class UserResource {
    @Resource(name = "getUser2")
    private User user;

    public void Hi(){
        System.out.println(user.toString());
    }
}

这里我们去执行

package com;

import com.ganzhi.UserController;
import com.ganzhi.UserResource;
import com.ganzhi.UserTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.annotation.Resource;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * com.User:  
 * Date: 2023-04-05
 * Time: 17:55
 */
public class App {


    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Spring-config.xml");

        UserResource userResource =  applicationContext.getBean("userResource", UserResource.class);
        userResource.Hi();
    }
}

就可以得到下面的结果

7.6.@Qualifier


如果我们实在想用Autowired就需要多添加一个这个注解来进行设置参数

 对UserResource进行修改

package com.ganzhi;

import com.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User:  
 * Date: 2023-04-08
 * Time: 17:29
 */
@Controller
public class UserResource {
//    @Resource(name = "getUser2")
    @Autowired
    @Qualifier(value = "getUser2")
    private User user;

    public void Hi(){
        System.out.println(user.toString());
    }
}

可以得到相同的结果

这里的value可以省略,直接写@Qualifier("getUser2")

到这里就结束了,感谢观看 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2022蓝桥杯省赛——卡片

问题描述 小蓝有 k 种卡片, 一个班有 n 位同学, 小蓝给每位同学发了两张卡片, 一位同学的两张卡片可能是同一种, 也可能是不同种, 两张卡片没有顺序。没有两位同学的卡片都是一样的。 给定 n, 请问小蓝的卡片至少有多少种? 输入格式 输入一行包含一个正整数表示 n 。 输出…

Vue中的slot插槽

目录 &#xff08;一&#xff09;什么是slot插槽 (1)slot插槽的作用 (2)插槽的好处和使用场景 &#xff08;3&#xff09;slot插槽的分类 1、默认插槽 2、具名插槽 3、作用域插槽 &#xff08;一&#xff09;什么是slot插槽 (1)slot插槽的作用 slot具有“占坑”的作用…

Hadoop MapReduce各阶段执行过程以及Python代码实现简单的WordCount程序

视频资料&#xff1a;黑马程序员大数据Hadoop入门视频教程&#xff0c;适合零基础自学的大数据Hadoop教程 文章目录Map阶段执行过程Reduce阶段执行过程Python代码实现MapReduce的WordCount实例mapper.pyreducer.py在Hadoop HDFS文件系统中运行Map阶段执行过程 把输入目录下文件…

【GoF 23 概念理解】AOP面向切面编程

1. 什么是AOP——面向切面编程 AOP是一种编程范式&#xff0c;提供了一种从宁一个角度来考虑程序结构以完善面向对象编程&#xff08;OOP&#xff09; AOP是一个思想上的变化——主从换位&#xff0c;让原本主动调用的模块变成了被动等待&#xff0c;甚至在毫不知情的情况下被…

CodeTON Round 4 (Div. 1 + Div. 2, Rated, Prizes!)A~E

比赛连接&#xff1a;Dashboard - CodeTON Round 4 (Div. 1 Div. 2, Rated, Prizes!) - Codeforces A. Beautiful Sequence 题意&#xff1a; t(1≤t≤500)组测试每组给定大小为n(1≤n≤100) 的序列&#xff0c;判断它是否存在一个子序列是好序列。一个序列是好序列当且仅当至…

GPT-3:大语言模型小样本学习

论文标题&#xff1a;Language Models are Few-Shot Learners论文链接&#xff1a;https://arxiv.org/abs/2005.14165论文来源&#xff1a;OpenAI一、概述自然语言处理已经从学习特定任务的表示和设计特定任务的架构转变为使用任务无关的预训练和任务无关的架构。这种转变导致了…

Python - Huffman Tree 霍夫曼树实现与应用

目录 一.引言 二.Huffman Tree 理论 1.定义 2.结构 3.构造 三.Huffman Tree 实现 1.生成霍夫曼树 2.编码霍夫曼编码 3.解码霍夫曼编码 4.霍夫曼树编码解码实践 四.总结 一.引言 上篇 Word2vec 的文章中指出每次计算词库 N 个单词的 Softmax 计算量很大&#xff0c;…

办公工具-latex

一、排版总论 1.1 缺省权力 ​ 首先&#xff0c;最重要最需要强调的是&#xff0c;排版是一个信息量极大的工程。字体&#xff0c;格式&#xff0c;对齐方式&#xff0c;页眉页脚&#xff0c;都只是排版的冰山一角&#xff0c;可以说&#xff0c;一个人是没有办法完全控制一个…

JVM 运行时数据区概述及线程

当我们通过前面的&#xff1a;类的加载 --> 验证 --> 准备 --> 解析 --> 初始化&#xff0c;这几个阶段完成后&#xff0c;就会用到执行引擎对我们的类进行使用&#xff0c;同时执行引擎将会使用到我们运行时数据区。 运行时数据区结构 内存概念&#xff1a; 内存…

leetcode:只出现一次的数字 Ⅲ(详解)

前言&#xff1a;内容包括&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读 题目&#xff1a; 给你一个整数数组 nums&#xff0c;其中恰好有两个元素只出现一次&#xff0c;其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任…

Qt界面编程(三)—— 父子关系、对象树、信号和槽(自定义信号和槽、Qt5与Qt4的写法)

一、Qt按钮小程序 1. 按钮的创建和父子关系 在Qt程序中&#xff0c;最常用的控件之一就是按钮了&#xff0c;首先我们来看下如何创建一个按钮&#xff1a; #include <QPushButton>QPushButton * btn new QPushButton; //设置父亲btn->setParent(this);//设置文字b…

接口测试-postman使用总结

一、为何使用postman postman是一款简单高效的接口测试工具&#xff0c;能够很方便发送接口请求&#xff0c;易于保存接口请求脚本&#xff0c;postman提供接口响应数据比对功能&#xff0c;可以设置预期结果作断言&#xff0c;还能把测试用例放在一个集合中批量执行&#xff…

【JavaWeb】9—监听器

⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记链接&#x1f449;https://github.com/A-BigTree/Code_Learning ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个star~&#x1f60a; 如果文章对你有所帮助&#xff0c;可以点赞&#x1f44d;…

torchvision.transforms 常用方法解析(含图例代码以及参数解释)

本文代码和图片完全源于 官方文档: TRANSFORMING AND AUGMENTING IMAGES 中的 Illustration of transforms&#xff0c;参数介绍源自函数对应的官方文档。 代码中的变换仅仅使用了最简单的参数&#xff1a;pad&#xff0c;size 等&#xff0c;这里展现的只是简单的变换&#xf…

C/C++每日一练(20230408)

目录 1. 删除无效的括号 &#x1f31f;&#x1f31f;&#x1f31f; 2. 合并K个升序链表 &#x1f31f;&#x1f31f;&#x1f31f; 3. 四数之和 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 …

SQL Server用户定义的函数(UDF)使用详解

SQL Server用户定义的函数一、背景知识1.1、用户定义函数的优点1.2、函数类型1.3、指引1.4、函数中的有效语句1.5、架构绑定函数1.6、指定参数二、创建用户定义函数2.1、限制和权限2.2、标量函数示例&#xff08;标量 UDF&#xff09;2.3、表值函数示例2.3.1、内联表值函数 &am…

项目管理软件调度的优势有哪些?

如果没有项目时间表&#xff0c;要跟踪在何时以及必须使用哪些资源之前需要完成什么是非常困难和耗时的。时间表是一个时间表&#xff0c;它概述了所有项目任务和需要完成的里程碑的开始和结束日期。 项目进度中的任务将具有依赖性&#xff0c;这意味着如果完成数据在一项活动上…

Redis7高级之Redlock算法和Redisson的使用(十)

10.1 Redlock 红锁算法 1.解决手写分布式锁的单点故障问题 Redis 提供了 Redlock 算法&#xff0c;用来实现基于多个实例的分布式锁锁变量由多个实例维护&#xff0c;即使有实例发生了故障&#xff0c;锁变量仍然是存在的&#xff0c;客户端还是可以完成锁操作Redlock算法是实…

计算机网络考试复习——第一章 1.5 1.6

1.5 计算机网络的类别 1.5.1计算机网络的定义&#xff1a; 系统集合&#xff0c;连接起来&#xff0c;协议工作&#xff0c;资源共享 计算机网络主要是由一些通用的、可编程的硬件互连而成的&#xff0c;而这些硬件并非专门用来实现某一特定目的&#xff08;例如&#xff0…

Java源码(一)ThreadLocal、SpringBoot Jar 启动原理

思维导图 一、ThreadLocal 1.场景 项目采用SSMShiro登录认证&#xff0c;改造需求如下&#xff1a; 后台管理员登录需要限制&#xff0c;同一个用户的不同IP需要通过过自定义验证后才能登录。 2.问题 在完成需求后发现有管理员用户&#xff08;这里就用A&#xff09;通过验…