Spring 中存储 Bean 的相关注解

在这里插入图片描述

Bean的存

IoC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象。
也就是bean的存储

类注解:五大注解

@Controller(控制器存储)
@Service(服务存储)
@Component(组件存储)
@Repository(仓库存储)
@Configuration(配置存储)
五大注解的存的过程都近似一样的,因此,下面我们就只介绍Controller的,其余的类似

@Controller(控制器存储)

使⽤@Controller存储bean的代码如下所⽰:

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

如何观察这个对象已经存在Spring容器当中了呢?
接下来我们学习如何从Spring容器中获取对象

@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
		//获取Spring上下⽂对象
		ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
		//从Spring上下⽂中获取对象
		UserController userController = context.getBean(UserController.class);
		//使⽤对象
		userController.doController();
	}
}

ApplicationContext翻译过来就是:Spring上下⽂,因为对象都交给Spring管理了,所以获取对象要从Spring中获取,那么就得先得到Spring的上下
这个上下⽂,就是指当前的运⾏环境,也可以看作是⼀个容器,容器⾥存了很多内容,这些内容是当前运⾏的环境
观察运⾏结果,发现成功从Spring中获取到Controller对象,并执⾏Controller的doController⽅法
在这里插入图片描述
如果把@Controller删掉,再观察运⾏结果
在这里插入图片描述
报错信息显⽰:找不到类型是:com.example.demo.controller.UserController的bean

获取bean对象的其他⽅式

上述代码是根据类型来查找对象,如果Spring容器中,同⼀个类型存在多个bean的话,怎么来获取呢?
ApplicationContext也提供了其他获取bean的⽅式,ApplicationContext获取bean对象的功能,是⽗类BeanFactory提供的功能.
在这里插入图片描述
常⽤的是上述1,2,4种,这三种⽅式,获取到的bean是⼀样的
其中1,2种都涉及到根据名称来获取对象.bean的名称是什么呢?
Spring bean是Spring框架在运⾏时管理的对象,Spring会给管理的对象起⼀个名字.
⽐如学校管理学⽣,会给每个学⽣分配⼀个学号,根据学号,就可以找到对应的学⽣.
Spring也是如此,给每个对象起⼀个名字,根据Bean的名称(BeanId)就可以获取到对应的对象.

Bean的命名约定

我们看下官⽅⽂档的说明:BeanOverview::SpringFramework
程序开发⼈员不需要为bean指定名称(BeanId),如果没有显式的提供名称(BeanId),Spring容器将为该bean⽣成唯⼀的名称.
命名约定使⽤Java标准约定作为实例字段名.也就是说,bean名称以⼩写字⺟开头,然后使⽤驼峰式⼤⼩写.
⽐如
类名:UserController,Bean的名称为:userController
类名:AccountManager,Bean的名称为:accountManager
类名:AccountService,Bean的名称为:accountService
也有⼀些特殊情况,当有多个字符并且第⼀个和第⼆个字符都是⼤写时,将保留原始的⼤⼩写.这些规则与java.beans.Introspector.decapitalize(Spring在这⾥使⽤的)定义的规则相同.
⽐如
类名:UController,Bean的名称为:UController
类名:AManager,Bean的名称为:AManager
根据这个命名规则,我们来获取Bean

		ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
		UserController userController = context.getBean(UserController.class);
		userController.doController();
		System.out.println(userController);
		UserController userController1 = (UserController)context.getBean("userController");
		userController1.doController();
		System.out.println(userController1);
		UserController userController2 = context.getBean("userController", UserController.class);
		userController2.doController();
		System.out.println(userController2);

在这里插入图片描述
地址⼀样,说明对象是⼀个
获取bean对象,是⽗类BeanFactory提供的功能
ApplicationContextVSBeanFactory(常⻅⾯试题)
• 继承关系和功能⽅⾯来说:Spring容器有两个顶级的接⼝:BeanFactory和
ApplicationContext。其中BeanFactory提供了基础的访问容器的能⼒,⽽
ApplicationContext属于BeanFactory的⼦类,它除了继承了BeanFactory的所有功能之外,它还拥有独特的特性,还添加了对国际化⽀持、资源访问⽀持、以及事件传播等⽅⾯的⽀持.
• 从性能⽅⾯来说:ApplicationContext是⼀次性加载并初始化所有的Bean对象,⽽
BeanFactory是需要那个才去加载那个,因此更加轻量.(空间换时间)

为什么要这么多类注解?

这个也是和咱们前⾯讲的应⽤分层是呼应的.让程序员看到类注解之后,就能直接了解当前类的⽤途.
• @Controller:控制层,接收请求,对请求进⾏处理,并进⾏响应.
• @Servie:业务逻辑层,处理具体的业务逻辑.
• @Repository:数据访问层,也称为持久层.负责数据访问操作
• @Configuration:配置层.处理项⽬中的⼀些配置信息.
这和每个省/市都有⾃⼰的⻋牌号是⼀样的.
⻋牌号都是唯⼀的,标识⼀个⻋辆的.但是为什么还需要设置不同的⻋牌开头呢.
⽐如陕西的⻋牌号就是:陕X:XXXXXX,北京的⻋牌号:京X:XXXXXX,甚⾄⼀个省不同的县区也是不同的,⽐如西安就是,陕A:XXXXX,咸阳:陕B:XXXXXX,宝鸡,陕C:XXXXXX,⼀样.
这样做的好处除了可以节约号码之外,更重要的作⽤是可以直观的标识⼀辆⻋的归属地.
程序的应⽤分层,调⽤流程如下:
在这里插入图片描述
类注解之间的关系
查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发
现:
在这里插入图片描述
在这里插入图片描述
其实这些注解⾥⾯都有⼀个注解@Component,说明它们本⾝就是属于@Component 的“⼦类”.
@Component 是⼀个元注解,也就是说可以注解其他类注解,如 @Controller ,@Service ,@Repository 等.这些注解被称为 @Component 的衍⽣注解.
@Controller ,@Service 和 @Repository ⽤于更具体的⽤例(分别在控制层,业务逻辑层,持久化层),在开发过程中,如果你要在业务逻辑层使⽤ @Component 或@Service,显然@Service是更好的选择

方法注解:@Bean

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

  1. 使⽤外部包⾥的类,没办法添加类注解
  2. ⼀个类,需要多个对象,⽐如多个数据源
    这种场景,我们就需要使⽤⽅法注解@Bean
    我们先来看看⽅法注解如何使⽤:
@Bean
    public UserInfo userInfo1(){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setAge(26);
        userInfo.setName("zhangsan");
        return userInfo;
    }

然⽽,当我们写完以上代码,尝试获取bean对象中的user时却发现,根本获取不到:

        UserInfo contextBean = context.getBean(UserInfo.class);
		System.out.println(contextBean);

在这里插入图片描述
这是为什么呢?

⽅法注解要配合类注解使⽤

在Spring框架的设计中,⽅法注解 @Bean 要配合类注解才能将对象正常的存储到Spring容器中,
如下代码所⽰:


@Controller
public class BeanController {
    @Bean
    public UserInfo userInfo1(){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setAge(26);
        userInfo.setName("zhangsan");
        return userInfo;
    }
 }

在这里插入图片描述

定义多个对象

对于同⼀个类,如何定义多个对象呢?
⽐如多数据源的场景,类是同⼀个,但是配置不同,指向不同的数据源.
我们看下@Bean的使⽤

    @Bean
    public UserInfo userInfo1(){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setAge(26);
        userInfo.setName("zhangsan");
        return userInfo;
    }
    @Bean
    public UserInfo userInfo2(){
        UserInfo userInfo = new UserInfo();
        userInfo.setName("lisi");
        userInfo.setId(2);
        userInfo.setAge(39);
        return userInfo;
    }

在这里插入图片描述
报错信息显⽰:期望只有⼀个匹配,结果发现了两个,user1,user2
从报错信息中,可以看出来,@Bean注解的bean,bean的名称就是它的⽅法名
接下来我们根据名称来获取bean对象

        UserInfo userInfo1 = (UserInfo)context.getBean("userInfo1");
		System.out.println(userInfo1);
		UserInfo userInfo2 = (UserInfo)context.getBean("userInfo2");
		System.out.println(userInfo2);

在这里插入图片描述

重命名 Bean

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

    @Bean(name = {"u1","userInfo1"})
    public UserInfo userInfo1(){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setAge(26);
        userInfo.setName("zhangsan");
        return userInfo;
    }
    @Bean(name = {"u2", "userInfo2"})
    public UserInfo userInfo2(){
        UserInfo userInfo = new UserInfo();
        userInfo.setName("lisi");
        userInfo.setId(2);
        userInfo.setAge(39);
        return userInfo;
    }
		UserInfo userInfo1 = (UserInfo)context.getBean("u1");
		System.out.println(userInfo1);
		UserInfo userInfo2 = (UserInfo)context.getBean("u2");
		System.out.println(userInfo2);

在这里插入图片描述
name={}可以省略,如下代码所⽰:

    @Bean({"u1","userInfo1"})

只有⼀个名称时,{}也可以省略,如:

    @Bean("u1")

注意:类注解的五大注解也可以使用该方法进行重命名操作

Bean的取

上⾯我们讲解了控制反转IoC的细节,接下来呢,我们学习依赖注⼊DI的细节,依赖注⼊是⼀个过程,是指IoC容器在创建Bean时,去提供运⾏时所依赖的资源,⽽资源指的就是对象.简单来说,就是把对象取出来放到某个类的属性中.在⼀些⽂章中,依赖注⼊也被称之为"对象注⼊",“属性装配”,具体含义需要结合⽂章的上下⽂来理解
关于依赖注⼊,Spring也给我们提供了三种⽅式:

  1. 属性注⼊(Field Injection)
  2. 构造⽅法注⼊(Constructor Injection)
  3. Setter注⼊(Setter Injection)
  4. 接下来,我们分别来看。
    下⾯我们按照实际开发中的模式,将Service类注⼊到Controller类中

属性注⼊

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

@Service
public class UserService {
    public void doService(){
        System.out.println("do service");
    }
}

Controller类的实现代码如下:

@Controller
public class UserController {
    @Autowired
    private UserService userService;
    public void doController(){
        userService.doService();
        System.out.println("do controller");
    }
}

获取Controller中的doController⽅法

ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
		UserController userController = context.getBean(UserController.class);
		userController.doController();

在这里插入图片描述
去掉@Autowired,再运⾏⼀下程序看看结果
在这里插入图片描述

构造⽅法注⼊

@Controller
public class UserController {
//    @Autowired

    private UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    public void doController(){
        userService.doService();
        System.out.println("do controller");
    }
}

在这里插入图片描述

注意事项:如果类只有⼀个构造⽅法,那么@Autowired注解可以省略;如果类中有多个构造⽅法,
那么需要添加上@Autowired来明确指定到底使⽤哪个构造⽅法

@Controller
public class UserController {
//    @Autowired

    private UserService userService;

    public UserController() {
    }

    public UserController(UserService userService) {
        this.userService = userService;
    }

    public void doController(){
        userService.doService();
        System.out.println("do controller");
    }
}

在这里插入图片描述


@Controller
public class UserController {
//    @Autowired

    private UserService userService;

    public UserController() {
    }
@Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    public void doController(){
        userService.doService();
        System.out.println("do controller");
    }
}

在这里插入图片描述

Setter注⼊

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

@Controller
public class UserController {
//    @Autowired

    private UserService userService;
@Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void doController(){
        userService.doService();
        System.out.println("do controller");
    }
}

在这里插入图片描述

三种注⼊优缺点分析

属性注⼊
◦ 优点:简洁,使⽤⽅便;
◦ 缺点:
▪ 1.只能⽤于IoC容器,如果是⾮IoC容器不可⽤,并且只有在使⽤的时候才会出现NPE(空指针异常)
▪ 不能注⼊⼀个Final修饰的属性
• 构造函数注⼊(Spring4.X推荐)
◦ 优点:
▪ 1.可以注⼊final修饰的属性
▪ 2.注⼊的对象不会被修改
▪ 3.依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法是在类加载阶段就会执⾏的⽅法。
▪ 4.通⽤性好,构造⽅法是JDK⽀持的,所以更换任何框架,他都是适⽤的
◦ 缺点:
▪ 注⼊多个对象时,代码会⽐较繁琐
• Setter注⼊(Spring3.X推荐)
◦ 优点:⽅便在类实例之后,重新对该对象进⾏配置或者注⼊
◦ 缺点:
▪ 1.不能注⼊⼀个Final修饰的属性
▪ 2.注⼊对象可能会被改变,因为setter⽅法可能会被多次调⽤,就有被修改的⻛险
更多DI相关内容参考:Dependencies :: Spring Framework

@Autowired存在问题

当同⼀类型存在多个bean时,使⽤@Autowired会存在问题

  @Bean("u1")
    public UserInfo userInfo1(){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setAge(26);
        userInfo.setName("zhangsan");
        return userInfo;
    }
    @Bean(name = {"u2", "userInfo2"})
    public UserInfo userInfo2(){
        UserInfo userInfo = new UserInfo();
        userInfo.setName("lisi");
        userInfo.setId(2);
        userInfo.setAge(39);
        return userInfo;
    }
@Controller
public class UserController {
//    @Autowired

    private UserService userService;
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    @Autowired
    private UserInfo userInfo;
    public void doController(){
        userService.doService();
        System.out.println("do controller");
        System.out.println(userInfo);
    }
}

在这里插入图片描述
如何解决上述问题呢?Spring提供了以下⼏种解决⽅案:

@Primary

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

 @Primary
    @Bean("u1")
    public UserInfo userInfo1(){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setAge(26);
        userInfo.setName("zhangsan");
        return userInfo;
    }

在这里插入图片描述

@Qualifier

使⽤@Qualifier注解:指定当前要注⼊的bean对象。在@Qualifier的value属性中,指定注⼊的bean的名称
@Qualifier注解不能单独使⽤,必须配合@Autowired使⽤

@Controller
public class UserController {
//    @Autowired

    private UserService userService;
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    @Qualifier("u2")
    @Autowired
    private UserInfo userInfo;
    public void doController(){
        userService.doService();
        System.out.println("do controller");
        System.out.println(userInfo);
    }
}

在这里插入图片描述

@Resource

使⽤@Resource注解:是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称

@Controller
public class UserController {
//    @Autowired

    private UserService userService;
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
//    @Qualifier("u2")
//    @Autowired
    @Resource(name = "u1")
    private UserInfo userInfo;
    public void doController(){
        userService.doService();
        System.out.println("do controller");
        System.out.println(userInfo);
    }
}

在这里插入图片描述
⾯试题:@Autowird与@Resource的区别
• @Autowired是spring框架提供的注解,⽽@Resource是JDK提供的注解
• @Autowired默认是按照类型注⼊,⽽@Resource是按照名称注⼊
@Autowired和@Resource的区别
• @Autowired来⾃于Spring,⽽@Resource来⾃于JDK的注解
• 使⽤时设置的参数不同:相⽐于@Autowired来说,@Resource⽀持更多的参数设置,例如name设置,根据名称获取Bean

bean的命名

1)五⼤注解存储的bean
①前两位字⺟均为⼤写,bean名称为类名
②其他的为类名⾸字⺟⼩写
③通过value属性设置 @Controller(value = “user”)
2)@Bean注解存储的bean
①bean名称为⽅法名
②通过name属性设置 @Bean(name = {“u1”,“user1”})

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

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

相关文章

介绍比特币上的 sCrypt 开发平台

最强大的基础设施和工具套件,可轻松构建和扩展您的 dApp 杀手级应用在哪里? 尽管比特币在小额支付、国际汇款和供应链管理等广泛用例中具有颠覆性潜力,但在推出 14 年后,我们还没有看到一款非常受欢迎并被主流采用的杀手级应用。 …

C++基础 -4- C/C++混合编程

引用格式(图片代码段呈现) extern "C" {#include "string.h" }代码验证 (分别使用了C/C 的标准输出) #include "iostream"using namespace std;extern "C" { #include "stdio.h" #include "…

前端学习系列之html

目录 初识html 发展史 优势 W3C 标准 地址 格式 网页基本标签 标题标签 段落标签 换行标签 水平线标签 字体样式 注释和特殊符号 特殊符号 图像、超链接 图像 常见图像格式 格式 超链接 格式 重要属性 href:规定链接指向的页面的 URL target…

【GO】k8s 管理系统项目16[前端部分--项目初始化]-学习记录

学习链接 https://blog.csdn.net/qq_29974229/article/details/129119279?spm1001.2014.3001.5502 nvm use v16.15.0 npm install vue -g npm install -g vue/clivue create k8s-plantform-fe选择 Default cd k8s-plantform-fe npm run servecd ./src mkdir views mkdir r…

华北高温背后的隐忧,双碳最大的障碍之一藏在这里

高温天气带来的庞大用电负荷,再一次让人们想到能源紧张问题和节能减碳的必要性。 然而,在日常企业经营中,由于员工缺乏对公共财产的成本意识,往往造成电力资源的巨大浪费。节能减碳,必须与精细化管理相结合&#xff0c…

《opencv实用探索·三》opencv Mat与数组互转

1、利用Mat来存储数据&#xff0c;避免使用数组等操作 //创建一个两行一列的矩阵cv::Mat mean (cv::Mat_<float>(2, 1) << 0.77, 0.33);std::cout() << mean << std::endl;float a mean.at<float>(0, 0); //0.77float b mean.at<float&…

Springboot日志-logback

logback-spring.xml的配置项 共有一个父标签、两种属性、三个节点: 一个父标签&#xff1a;configuration 两种属性&#xff1a;contextName和property 三个节点&#xff1a;appender、root、logger 日志级别 日志级别从低到高分为TRACE < DEBUG < INFO < WARN &…

RabbitMQ工作模式2 整合springboot 和MQ高级特性

RabbitMQ工作模式 1.路由模式 创建交换机 , 连接队列 (生产者) public class MyTestExDirect {Testpublic void bbb() throws IOException, TimeoutException {ConnectionFactory connectionFactory new ConnectionFactory();//连接mqconnectionFactory.setUsername("…

ZYNQ PL 中断请求

1 中断概念 中断学习 2 ZYNQ 中断框图 上图为 zynq 中断分布框图。可以看到部分 PL 到 PS 部分的中断&#xff0c;经过中断控制分配器&#xff08;ICD&#xff09;&#xff0c; 同时进入 CPU1 和 CPU0。查询下面表格&#xff0c;可以看到 PL 到 PS 部分一共有 20 个中断可以使…

qt国际化多语言

vs + qt 方法 一 (1)生成.pro文件 如果报错: cannot find any qt projects to export 则执行如下: 然后重新生成 pro文件。 (2)生成ts文件 (方法1)在项目文件(xxx.pro) 文件添加: TRANSLATIONS += en.ts zh_CN.ts 然后打开cmd命令,进入项目目录,执行 l…

C++中的new、operator new与placement new

new operator new operator是我们常用的new。 new 和 delete 是用来在 堆上申请和释放空间的 &#xff0c;是 C 定义的 关键字&#xff0c;和 sizeof 一样。 实际 new / delete 和 malloc / free 最大的区别是&#xff0c;前者对于 自定义类型 除了可以开辟空间&#xff0c;…

C语言基础篇5:指针(二)

接上篇&#xff1a;C语言基础篇5&#xff1a;指针(一) 4 指针作为函数参数 4.1 指针变量作为函数的参数 指针型变量可以作为函数的参数&#xff0c;使用指针作为函数的参数是将函数的参数声明为一个指针&#xff0c;前面提到当数组作为函数的实参时&#xff0c;值传递数组的地址…

其利天下技术总监冯建武受邀出席“2023年电子工程师大会”并作主题演讲

2023年11月23日&#xff0c;由华秋电子发烧友主办的“2023年电子工程师大会暨第三届社区年度颁奖活动”在深圳新一代产业园成功举行。本次年度颁奖活动邀请了高校教授、企业高管、行业专家、资深电子工程师等共300多人出席。聚焦“电机驱动技术”、“开源硬件”、“OpenHarmony…

C#学习-8课时

P10 输入输出程序编写 相同类型的可以直接相加&#xff1b; cwtabtabconsole.Writeline(); using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace C_8_1 { class Program { s…

【腾讯云云上实验室】用向量数据库—实践相亲社交应用

快速入口 &#x1f449;向量数据库_大模型知识库_向量数据存储_向量数据检索- 腾讯云 (tencent.com) 文章目录 前言1. 向量数据库概念及原理1.1 向量数据库概念1.2 向量数据库核心原理1.3 向量数据库优缺点1.4 向量数据库与传统数据库的区别 2. 腾讯云向量数据库的基本特性及优…

黑马程序员索引学习笔记

文章目录 索引的分类从索引字段特性从物理存储从数据结构组成索引的字段个数 InnoDB主键索的Btree高度为多高呢?explain执行计划最左匹配原则索引失效情况SQL提示覆盖索引、回表查询前缀索引索引设计原则 索引的分类 从索引字段特性 主键索引、唯一索引、常规索引、全文索引…

RNN 网络结构及训练过程简介

本文通过整理李宏毅老师的机器学习教程的内容&#xff0c;简要介绍 RNN&#xff08;recurrent neural network&#xff09;的网络结构及训练过程。 RNN 网络结构, 李宏毅 RNN RNN 的特点在于存储功能&#xff0c;即可以记忆前面时刻的信息。 最简单的 RNN 结构如下&#xf…

切换服务器上自己用户目录下的 conda 环境和一个外部的 Conda 环境

如果我们有自己的 Miniconda 安装和一个外部的 Conda 环境&#xff08;比如一个全局安装的 Anaconda&#xff09;&#xff0c;我们可以通过修改 shell 环境来切换使用它们。这通常涉及到更改 PATH 环境变量&#xff0c;以便指向你想要使用的 Conda 安装的可执行文件&#xff1a…

CSS新手入门笔记整理:CSS基本选择器

id属性 id属性具有唯一性&#xff0c;也就是说&#xff0c;在一个页面中相同的id只能出现一次。在不同的页面中&#xff0c;可以出现两个id相同的元素。 语法 <div id"text"> ...... </div> class属性 class&#xff0c;顾名思义&#xff0c;就是“类…

C语言每日一题(37)两数相加

力扣网 2 两数相加 题目描述 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&a…