spring-boot rabbitmq整合
文章请参考:Springboot 整合RabbitMq ,用心看完这一篇就够了
mven依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies>
配置rabbitmq
配置生产者
spring:rabbitmq:host: localhostport: 5672username: rootpassword: rootvirtual-host: pers-xrb
配置queue
@Beanpublic Queue TestDirectQueue(){return new Queue("direct-queue",true);}
Queue的构造函数如下:
Queue(String name, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
Queue有如下几个属性:
- name-the name of the queue - must not be null; set to “” to have the broker generate the name.(不能为空,如果想让服务器自动生成的话,那么设置为"")
- durable- true if we are declaring a durable queue (the queue will survive a server restart)(是否持久化,如果想在服务器重启的时候仍然存在,那么设置为true,默认和推荐设置为true)
- exclusive-true if we are declaring an exclusive queue (the queue will only be used by the declarer’s connection) (排他性,默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable)
- autoDelete-true if the server should delete the queue when it is no longer in use(自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除,默认是false)
所以通常的初始化构造函数是

配置exchange
@BeanDirectExchange TestDirectExchange() {return new DirectExchange("TestDirectExchange", true, false);}
绑定
@BeanBinding bindingDirect() {return BindingBuilder.bind(TestDirectQueue()).to(TestDirectExchange()).with("TestDirectRouting");}
配置触发器
@RestController("/rabbit-mq-sender")
public class SendMessageController {private final RabbitTemplate rabbitTemplate;public SendMessageController(RabbitTemplate rabbitTemplate) {this.rabbitTemplate = rabbitTemplate;}@GetMapping("/sendDirectMessage")public String sendDirectMessage() {String messageId = String.valueOf(UUID.randomUUID());String messageData = "test message, hello!";String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));Map<String, Object> map = new HashMap<>(3);map.put("messageId", messageId);map.put("messageData", messageData);map.put("createTime", createTime);//将消息携带绑定键值:TestDirectRouting 发送到交换机TestDirectExchangerabbitTemplate.convertAndSend("TestDirectExchange","TestDirectRouting", map);return "ok";}
}
发送后,可以看到ui界面的信息

配置消费者
基本配置和配置生产者没有什么区别,除了这里需要配置的是监听器和指定监听器的处理器,声明消费者类为监听器@DirectReceiver,指定方法为处理器@RabbitHandler
@Service
@Slf4j
@RabbitListener(queues = "TestDirectQueue") // 指定监听的队列
public class DirectReceiver {@RabbitHandlerpublic void process(Object testMessage) {try {TimeUnit.SECONDS.sleep(1);log.debug("DirectReceiver[TestDirectQueue]消费者收到消息 : " + testMessage.toString());} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
启动服务器后,就可以直接监听和消费mq信息了,如果需要增加一个消费者,那么copy一个DirectReceiver实例,命名为DirectReceiver2就行了。默认的消费策略是轮询策略,这个方法待优化,很明显在现实开发过程中是不可能这么写的。
生产者的confirm和return机制
RabbitMq发消息的流程

从上面的图,我们可以看到一个mq发送的话,可能会出现如下几种情况
- 未找到交换机
- 找到交换机,但是未绑定queue
- 找到了queue,消息推送成功
confirm机制
confirm机制是对于生产者和服务器broker来说的。
生产者将信道设置成confirm模式,一旦信道进入confirm模式,所有在该信道上面发布的消息都会被指派一个唯一的ID(从1开始,单调递增),一旦消息被投递到所有匹配的队列之后,broker就会发送一个ACK给生产者(包含消息的唯一ID)

return机制
returnCallback 未投递到queue退回模式
confrim 模式只能保证消息到达 broker,不能保证消息准确投递到目标 queue 里。在有些业务场景下,我们需要保证消息一定要投递到目标 queue 里,此时就需要用到 return 退回模式。这里需要exchange触发无法查找queue的场景,也就是说exchange存在,但是queue不存在
配置confirm和return
- 修改yml配置
spring:rabbitmq:host: localhostport: 5672username: rootpassword: rootvirtual-host: pers-xrbpublisher-confirms: true #确认消息已发送到交换机(Exchange)publisher-returns: true #确认消息已发送到队列(Queue)
- 自定义rabbitMqTemplate
@Beanpublic RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate();rabbitTemplate.setConnectionFactory(connectionFactory);//设置开启Mandatory,才能触发回调函数,无论消息推送结果怎么样都强制调用回调函数rabbitTemplate.setMandatory(true);rabbitTemplate.addAfterReceivePostProcessors(message -> {byte[] body = message.getBody();log.info("received body is:{}", body);return message;});// set confirm callbackrabbitTemplate.setConfirmCallback((correlationData, isAck, cause) -> {System.out.println("ConfirmCallback: " + "相关数据:" + correlationData);System.out.println("ConfirmCallback: " + "确认情况:" + isAck);System.out.println("ConfirmCallback: " + "原因:" + cause);});// set return callbackrabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {System.out.println("ReturnCallback: " + "消息:" + message);System.out.println("ReturnCallback: " + "回应码:" + replyCode);System.out.println("ReturnCallback: " + "回应信息:" + replyText);System.out.println("ReturnCallback: " + "交换机:" + exchange);System.out.println("ReturnCallback: " + "路由键:" + routingKey);});return rabbitTemplate;}
- 增加触发接口
private static Map<String, Object> getMqMessage() {String messageId = String.valueOf(UUID.randomUUID());String messageData = "test message, hello!";String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));Map<String, Object> map = new HashMap<>(3);map.put("messageId", messageId);map.put("messageData", messageData);map.put("createTime", createTime);return map;}/*** 4.1 exchange and queue not exist*/@GetMapping("/sendNotExistExchangeMessage")public String sendNotExistExchangeMessage() {Map<String, Object> map = getMqMessage();//将消息携带绑定键值:TestDirectRouting 发送到交换机TestDirectExchangerabbitTemplate.convertAndSend("NotExistExchangeExchange","NotExistExchangeExchangeQueue", map);return "ok";}/*** 4.2 exchange exist but queue not exist*/@GetMapping("/sendNotExistQueueButExchangeMessage")public String sendNotExistQueueButExchangeMessage() {Map<String, Object> map = getMqMessage();//将消息携带绑定键值:TestDirectRouting 发送到交换机TestDirectExchangerabbitTemplate.convertAndSend("NotExistQueueButExchangeExchange","NotExistQueueButExchangeQueue", map);return "ok";}
- 测试
为了测试两种情形,我们分别为- 交换机exchange不存在
- 交换机存在但是队列不存在
- exchange和queue都存在
4.1 交换机exchange不存在
调用对应的接口 http://localhost:9876/rabbit-mq-sender/sendNotExistExchangeMessage
在日志台会出现如下信息:

这个时候只会调用confirmcallback,confirmcallback会告诉你这个exchange是不存在的。
4.2,交换机存在但是queue不存在的场景,
我们调用对应的api接口
http://localhost:9876/rabbit-mq-sender/sendNotExistQueueButExchangeMessage
不过在这之前,我们需要先在声明一个exchange
/*** Direct交换机 起名:NotExistQueueButExchangeExchange*/@BeanDirectExchange NotExistQueueButExchange() {return new DirectExchange("NotExistQueueButExchangeExchange", true, false);}
查看日志台,信息如下:

我们会发现,confirmcallback和returnCallback两个函数其实都是调用了的,在confirmcallback中,返回结果告诉了我们isAck是true的,但是returnCallback中告诉我们No_route,表示没有找到对应的路由
,在exchange的ui中,我们可以看到我们有两个exchange

4.3 那如果所有的都是正常的呢?[confirm|return]callback会返回什么呢?我们调用api测试下:
http://localhost:9876/rabbit-mq-sender/sendDirectMessage
日志台结果如下:

这个时候是只调用confirmCallback的
消费者接收到消息的消费确认机制
如果消费者消费后怎么告诉rabbitmq服务器呢?通常来说消费者消费后会返回一个信息给服务器表达了服务器已经接受并且告诉服务器消费结果和后续的处理,总结来说,消费者要告诉消费者如下消息
- 是否消费成功-这决定服务器是否要删除消息
- 如果消费失败,那么需要重新放回队列吗?
消费者接收的确认机制主要存在三种模式
- 自动确认,这也是默认的消息确认情况。 AcknowledgeMode.NONE
RabbitMQ成功将消息发出(即将消息成功写入TCP Socket)中立即认为本次投递已经被正确处理,不管消费者端是否成功处理本次投递。
所以这种情况如果消费端消费逻辑抛出异常,也就是消费端没有处理成功这条消息,那么就相当于丢失了消息。
一般这种情况我们都是使用try catch捕捉异常后,打印日志用于追踪数据,这样找出对应数据再做后续处理。
- 根据业务来处理,这个根据自己的业务需求来处理,不细说
- 手动确认, 这个比较关键,也是我们配置接收消息确认机制时,多数选择的模式。
消费者收到消息后,手动调用basic.ack/basic.nack/basic.reject后,RabbitMQ收到这些消息后,才认为本次投递成功,换句话说,这也是和业务做耦合的。
消费者收到消息后,手动调用对应的方法后,RabbitMQ收到这些消息后,才认为本次投递成功。手动确认分如下情况,消费成功和消费失败。
1. basicAck用于肯定确认
2. basicNack用于否认确定
3. basicReject 用于否认确认,但和basic.nack相比有一个限制,一次只能拒绝单条信息
basic.reject
basicReject 表示否认确认,
/*** Reject a message. Supply the deliveryTag from the {@link com.rabbitmq.client.AMQP.Basic.GetOk}* or {@link com.rabbitmq.client.AMQP.Basic.Deliver} method* containing the received message being rejected.* @see com.rabbitmq.client.AMQP.Basic.Reject* @param deliveryTag the tag from the received {@link com.rabbitmq.client.AMQP.Basic.GetOk} or {@link com.rabbitmq.client.AMQP.Basic.Deliver}* @param requeue true if the rejected message should be requeued rather than discarded/dead-lettered* @throws java.io.IOException if an error is encountered*/void basicReject(long deliveryTag, boolean requeue) throws IOException;
入参有两个
- deliveryTag-消息体发送标志,不细说
- requeue-是否重新放在队列中,次还会消费这消息。设置false,就是告诉服务器,我已经知道这条消息数据了,因为一些原因拒绝它,而且服务器也把这个消息丢掉就行。 下次不想再消费这条消息了。
使用拒绝后重新入列这个确认模式要谨慎,因为一般都是出现异常的时候,catch异常再拒绝入列,选择是否重入列。
但是如果使用不当会导致一些每次都被你重入列的消息一直消费-入列-消费-入列这样循环,会导致消息积压。
channel.basicNack
也是相当于设置不消费某条消息。
源码如下
/*** Reject one or several received messages.** Supply the <code>deliveryTag</code> from the {@link com.rabbitmq.client.AMQP.Basic.GetOk}* or {@link com.rabbitmq.client.AMQP.Basic.GetOk} method containing the message to be rejected.* @see com.rabbitmq.client.AMQP.Basic.Nack* @param deliveryTag the tag from the received {@link com.rabbitmq.client.AMQP.Basic.GetOk} or {@link com.rabbitmq.client.AMQP.Basic.Deliver}* @param multiple true to reject all messages up to and including* the supplied delivery tag; false to reject just the supplied* delivery tag.* @param requeue true if the rejected message(s) should be requeued rather* than discarded/dead-lettered* @throws java.io.IOException if an error is encountered*/void basicNack(long deliveryTag, boolean multiple, boolean requeue)throws IOException;
Reject one or several received messages,很显然是否认一个或多个接受到的消息体,重点是第二个参数:是指是否针对多条消息;如果是true,也就是说一次性针对当前通道的消息的tagID小于当前这条消息的,都拒绝确认。
同样使用不确认后重新入列这个确认模式要谨慎,因为这里也可能因为考虑不周出现消息一直被重新丢回去的情况,导致积压。
消费者消费机制case(在消费者项目里)
- 首先,我们需要设定一个通用的receiver,这个receiver是通用的receiver(之前的相关监听器可以先注释掉,以免造成多个同类型监听器都监听同一个队列。如果有的话)
public class MyAckMessageReceiver implements ChannelAwareMessageListener {@Overridepublic void onMessage(Message message, Channel channel) throws Exception {long deliveryTag = message.getMessageProperties().getDeliveryTag();String strictRequired = null;try {byte[] body = message.getBody();ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(body));Map<String, String> msgMap = (Map<String, String>) ois.readObject();String messageId = msgMap.get("messageId");String messageData = msgMap.get("messageData");String createTime = msgMap.get("createTime");strictRequired = msgMap.get("strictRequired");ois.close();System.out.println(" MyAckReceiver messageId:" + messageId + " messageData:" + messageData + " createTime:" + createTime);System.out.println("消费的主题消息来自:" + message.getMessageProperties().getConsumerQueue());//第二个参数,手动确认可以被批处理,当该参数为 true 时,则可以一次性确认 delivery_tag 小于等于传入值的所有消息channel.basicAck(deliveryTag, true);} catch (IOException | ClassNotFoundException e) {boolean isRequeue = strictRequired != null && strictRequired.contains("1");channel.basicReject(deliveryTag, isRequeue);e.printStackTrace();}}
}
- 配置一个MessageListenerConfig,代码如下:
@Configuration
public class MessageListenerConfig {@BeanMyAckMessageReceiver messageReceiver() {return new MyAckMessageReceiver();}@Beanpublic SimpleMessageListenerContainer simpleMessageListenerContainer(CachingConnectionFactory connectionFactory,MyAckMessageReceiver myAckMessageReceiver) {SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);container.setConcurrentConsumers(1);container.setMaxConcurrentConsumers(1);container.setAcknowledgeMode(AcknowledgeMode.MANUAL); // RabbitMQ默认是自动确认,这里改为手动确认消息//设置一个队列container.setQueueNames("TestDirectQueue");//如果同时设置多个如下: 前提是队列都是必须已经创建存在的// container.setQueueNames("TestDirectQueue","TestDirectQueue2","TestDirectQueue3");//另一种设置队列的方法,如果使用这种情况,那么要设置多个,就使用addQueues//container.setQueues(new Queue("TestDirectQueue",true));//container.addQueues(new Queue("TestDirectQueue2",true));//container.addQueues(new Queue("TestDirectQueue3",true));container.setMessageListener(myAckMessageReceiver);return container;}
在container中指定消息队列和对应的receiver处理器
相关文章:
spring-boot rabbitmq整合
文章请参考:Springboot 整合RabbitMq ,用心看完这一篇就够了 mven依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></depende…...
CentOS7安装redis redis常用命令
Redis简介Redis是一个开源免费的、使用C语言编写的NoSQL 数据库。Redis基于内存运行并支持持久化(RDB、AOF方式将数据保存在磁盘),采用key-value (键值对)的存储形式。Redis数据类型Redis支持五种数据类型:string(字符串)…...
世界文明的脉络
人类文明大体上可分为农耕文明、海洋文明和游牧文明三大类别,文明的标志一般是文字、青铜器、城市以及礼仪性建筑等要素。据此,史学家目前已发现了巴比伦文明、埃及文明、印度文明、华夏文明、希腊文明和波斯文明六种主要文明,其中前四种文明…...
map和set 的封装
文章目录引入key-value模型map和set底层setset的几个重要接口mapmap几个重要的接口map和set的封装引入 对于map和set的引入,我们用一道在程序中常见的问题解决: 给定一个数组int arr[]{1,2,1,3,1,4,1,5,5,2,3,4,5};,给出以下问题的解决方案&…...
Springboot集成kafka(环境搭建+演示)|超级详细,建议收藏
Springboot集成kafka一、前言🔥二、环境说明🔥三、概念🔥四、CentOS7安装kafka🔥1.下载kafka安装包2.下载好后,进行解压六、kafka项目集成🔥1️⃣pom引入2️⃣配置kafka3️⃣一个kafka消息发送端4️⃣定义一…...
Qt 绘制图表 - Qt Charts版
一、前言 自从 Qt 发布以来,给广大跨平台界面研发人员带来了无数的福利。但是Qt自己却一直没有提供自带的图表库,这就使得 QWT、QCustomPlot 等第三方图表库有了巨大的生存空间,为了降低开发成本,大家都涌向了这些第三方库。这种…...
Java学习笔记 --- JavaScript
一、JavaScript介绍 JavaScript语言诞生主要是完成页面的数据验证。因此它运行在客户端,需要运行浏览器来解析执行JavaScript代码。JS是Netcape网景公司的产品,最早取名为LiveScript;为了吸引更多java程序员。更名为 JavaScript JS是弱类型&…...
AP5216 平均电流型LED 降压恒流驱动器
产品描述 AP5216 是一款 PWM工作模式, 高效率、外围简单、内置功率管,适用于5V~100V输入的高精度降压 LED 恒流驱动芯片。输出最大功率可达 9W,最大电流 1.0A。 AP5216 可实现全亮/半亮功能切换,通过MODE 切换:全亮/…...
B站的多个视频教程,怎样生成一个二维码?
商业插画视频教程、电商运营视频教程、在线网课视频、舞蹈视频教程、摄影视频教程、语言学习教程、纪录片视频…所有你发布在哔哩哔哩上的视频,都可以放在一个二维码里面。 任何人只要扫描这个二维码,就能在线观看你的这些视频教程!分享起来…...
深入底层源码的Listener内存马(内存马系列篇三)
写在前面 继前面的FilterServlet内存马技术,这是系列文章的第三篇了,这篇将给大家带来的是Listener内存马技术。 前置 什么是Listener? 监听器 Listener 是一个实现特定接口的 Java 程序,这个程序专门用于监听另一个 Java 对象…...
云端需求助力跑赢周期,金山办公有望借助ChatGPT加速腾飞
与微软在办公领域“搏杀”了三十年的金山办公,或许正在迎来自己的“第二春”。2月25日,金山办公(688111)发布2022年度业绩快报,全年营收38.85亿元人民币(单位下同),同比增加18.44%&a…...
Vulnhub靶场----8、DC-8
文章目录一、环境搭建二、渗透流程三、思路总结一、环境搭建 DC-8下载地址:https://download.vulnhub.com/dc/DC-8.zip kali:192.168.144.148 DC-8:192.168.144.156 二、渗透流程 1、信息收集nmap -T5 -A -p- -sV -sT 192.168.144.156思路&am…...
Makefile 和 Shell 脚本的区别与联系
以下内容转载于博客Makefile 和 shell 脚本的区别与联系,有删改与内容添加。 参考内容:初学Makefile指南 一、什么是 Makefile? Makefile 描述了整个工程的编译、链接规则。当源码文件比较多的时候就不适合通过输入 gcc 命令来编译…...
java25种设计模式之工厂模式
Java设计模式 - 工厂模式 工厂模式是一种创建模式,因为此模式提供了更好的方法来创建对象。 在工厂模式中,我们创建对象而不将创建逻辑暴露给客户端。 例子 在以下部分中,我们将展示如何使用工厂模式创建对象。 由工厂模式创建的对象将是…...
力扣-2020年最后一次登录
大家好,我是空空star,本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目:1890. 2020年最后一次登录二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.…...
[蓝桥杯] 数学与简单DP问题
文章目录 一、简单数学问题习题练习 1、1 买不到的数目 1、1、1 题目描述 1、1、2 题解关键思路与解答 1、2 饮料换购 1、2、1 题目描述 1、2、2 题解关键思路与解答 二、DP问题习题练习 2、1 背包问题 2、1、1 题目描述 2、1、2 题解关键思路与解答 2、2 摘花生 2、2、1 题目…...
浏览器的渲染过程解析
文章目录浏览器渲染进程有哪些?浏览器的渲染过程浏览器渲染进程有哪些? GUI线程:负责渲染浏览器页面,解析html,css,构建DOM树,CSS规则树,渲染树和绘制页面,当界面需要重…...
【C++容器】std::fstream读写文件错误【2023.03.03】
std::fstream使用细节 1.文件不存不支持时打开文件模式不得有ios::in • 如果文件不存在且打开时包括了ios::in模式则打开文件会失败。 fstream m_f;m_f.open("d://123.csv", ios::in | ios::out | ios::binary);//文件不存在则会打开失败• 我这边尝试行得通的做…...
UVM实战--带有寄存器的加法器
一.整体的设计结构图 这里将DUT换成加法器,可以理解为之前UVM加法器加上寄存器,这里总线的功能不做修改,目的看代码的移植那些部分需要修改。 二.各个组件代码详解 2.1 DUT module dut( input clk, input rst_n, input…...
笔记--学习mini3d代码
主要是记录学习mini3d代码时,查的资料; 从github下载的代码: GitHub - skywind3000/mini3d: 3D Software Renderer in 700 Lines !!3D Software Renderer in 700 Lines !! Contribute to skywind3000/mini3d development by creating an a…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
恶补电源:1.电桥
一、元器件的选择 搜索并选择电桥,再multisim中选择FWB,就有各种型号的电桥: 电桥是用来干嘛的呢? 它是一个由四个二极管搭成的“桥梁”形状的电路,用来把交流电(AC)变成直流电(DC)。…...
算法—栈系列
一:删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...
