Protocol Buffers 全流程通俗讲解
Protocol Buffers 全流程通俗讲解(从 0 到进阶)
目录
- 序列化到底为什么要选 Protobuf?
- 核心原理:一眼看懂二进制编码
- 10 分钟跑通「写 .proto → 生成代码 → 读写数据」
- .proto 文件 8 条黄金法则(小白友好版)
- 典型使用场景 & 选型心法
- 高级语法:oneof / map / Any / packed / custom options
- 性能调优与常用工具
- 常踩的坑 + FAQ
- 与 JSON / FlatBuffers / Thrift 对比
- 结语:把 .proto 当成“团队契约”
1. 序列化到底为什么要选 Protobuf?
特性 | JSON | XML | Protobuf |
---|---|---|---|
体积 | ⚠️ 文本臃肿 | ⚠️ 更臃肿 | 🏆 最小(3–10 倍压缩) |
编解码速度 | 中 | 慢 | 🏆 快(少字符串解析) |
数据自描述 | ✅(键=名字) | ✅ | ✅(Tag=编号+编码方式) |
向后兼容 | ⚠️ 改键就炸 | ⚠️ 同上 | 🏆 字段编号不变即可 |
多语言支持 | 广 | 广 | 🏆 官方+CNCF 插件体系 |
一句话:Protobuf = 紧凑 + 快速 + 可演进 + 跨语言。
2. 核心原理:一眼看懂二进制编码
写数据 = 写 Tag + Value
Tag =(field_number << 3) | wire_type
wire_type | 代表含义 | 典型字段 |
---|---|---|
0 | Varint(变长整数) | int32 / bool |
1 | 64 bit 固定长 | fixed64 / double |
2 | Length‑delimited | string / bytes / 嵌套 message |
5 | 32 bit 固定长 | fixed32 / float |
- Varint:按 7 bit 一段写,高位为 1 表示“后面还有”。小数字占 1 byte,大数字最多 10 byte。
- ZigZag:把有符号整数映射成无符号,负数也能享受小体积。
- Length‑delimited:先写长度,再写原始字节;字符串、嵌套消息全靠它。
解析器遇到 未知 Tag 直接跳过,所以旧代码能平稳处理新消息——这就是“向前兼容”的底气。
3. 10 分钟跑通「写 .proto → 生成代码 → 读写数据」
以 Windows + MSVC 为例,macOS/Linux 把
choco
换成brew
或apt
即可。
3.1 安装编译器
choco install protoc # 安装 protoc
protoc --version # 确认 ≥ 25.x
3.2 编写 .proto
// file: tutorial/addressbook.proto
syntax = "proto3";package tutorial; // 命名空间message Person {uint32 id = 1; // 编号必须唯一string name = 2;string email = 3;repeated string tags = 4; // 数组
}
3.3 一键生成 C++ 代码
protoc --cpp_out=. tutorial/addressbook.proto
# 得到 addressbook.pb.h / addressbook.pb.cc
3.4 编写 Demo
// file: demo.cpp
#include "addressbook.pb.h"
#include <fstream>
#include <iostream>int main() {GOOGLE_PROTOBUF_VERIFY_VERSION; // ① 运行时版本兼容检查tutorial::Person p; // ② 构建消息p.set_id(1001);p.set_name("小明");p.set_email("xiaoming@example.com");*p.add_tags() = "vip"; // ③ repeated 字段std::string bin;if (!p.SerializeToString(&bin)) { // ④ 序列化std::cerr << "serialize failed\n";return 1;}std::ofstream("person.bin", std::ios::binary).write(bin.data(), bin.size());tutorial::Person q;q.ParseFromString(bin); // ⑤ 反序列化std::cout << q.name() << " <" << q.email() << ">\n";google::protobuf::ShutdownProtobufLibrary();
}
3.5 编译运行
cl /EHsc demo.cpp addressbook.pb.cc ^/I"%ProgramFiles%\Google\protobuf\include" ^/link /LIBPATH:"%ProgramFiles%\Google\protobuf\lib" libprotobuf.lib
demo.exe
输出:小明 <xiaoming@example.com>
到此,你已经完成:写
.proto
→ 生成.h/.cc
→ C++ 里序列化/反序列化。剩下只是把流程复制到实际项目中。
4. .proto 文件 8 条黄金法则(小白友好版)
# | 规则一句话 | 通俗解释 | 小示例 |
---|---|---|---|
1 | 编号与类型永不改 | 编号像身份证;类型决定解析策略,改了旧代码全崩。 | 把 id = 1 从 int32 改成 string → 老版本读出来是乱码。 |
2 | 常用字段放 1‑15 | 1‑15 的 Tag 只占 1 byte,省流量。 | 聊天文本 content=2 比放 22 小一半字节。 |
3 | 删除前先 reserved | 声明曾用号,不让后来误占。 | reserved 4, "old_name"; |
4 | 文本用 string ,文件用 bytes | string 默认 UTF‑8;bytes 纯二进制。 | 头像用 bytes avatar = 5; |
5 | 远离 required | 升级难,proto3 直接砍掉。用 optional + 默认值。 | |
6 | 枚举值写非负整数 | 建议首值 0 表示“未设置”。删除也要 reserved 。 | enum Role { ROLE_NONE = 0; ADMIN = 1; } |
7 | package 决定命名空间 | 防止不同模块类名冲突。 | package shop.order.v1; → shop::order::v1::Order |
8 | 一文件一主题 | 文件小、易审阅;版本用目录区分。 | user/v1/user.proto , order/v2/order.proto |
5. 典型使用场景 & 选型心法
场景 | 为什么适合 Protobuf? |
---|---|
微服务 RPC | gRPC 默认载体,上下行小、延迟低。 |
移动/物联网 | 蜂窝流量计费,节省字节就是省钱。 |
游戏帧同步 | 每帧几十条消息,高频字段+变长整数特别省带宽。 |
Kafka 事件流 | 搭 Schema Registry,自动验证版本兼容。 |
配置/缓存文件 | 二进制快、也支持转 JSON 调试(官方 util)。 |
选型口诀:
‑ 要“读时 0 拷贝”→ FlatBuffers/Cap’n Proto;
‑ 要“好写+可演进”→ Protobuf 一般最合适。
6. 高级语法:oneof / map / Any / packed / custom options
6.1 oneof
——互斥字段省字节
message Shape {oneof kind {Circle circle = 1;Rectangle rect = 2;}
}
- 仅当前 set 的字段会写入字节流。
- 判断类型:
shape.kind_case() == Shape::kCircle
6.2 map<K,V>
——原生字典
map<string, int32> scores = 3; // 隐式转成 repeated pair
关键点:Key 不可用浮点 / bytes / message。
6.3 Any
——动态消息载体
import "google/protobuf/any.proto";
google.protobuf.Any body = 4;
使用:
google::protobuf::Any any;
any.PackFrom(myMessage); // 序列化
MyType msg;
any.UnpackTo(&msg); // 反序列化
6.4 packed
——批量数字压缩
repeated int32 points = 5 [packed = true]; // 在 proto3 默认已开启
6.5 custom options
——自定义注解
extend google.protobuf.FieldOptions {bool sensitive = 50001;
}message User {string phone = 1 [(sensitive) = true];
}
配合反射可自动做日志脱敏。
7. 性能调优与常用工具
技巧 / 工具 | 效果 |
---|---|
Arena | 批量对象一次性分配/回收,减 GC。 |
Lite runtime | --cpp_out=lite: ,体积 ↓60%,去掉反射。 |
Zero‑copy IO | SerializeToZeroCopyStream 少一次内存复制。 |
Buf | Lint + 违规变更检测 + 远端缓存。 |
protoc‑gen‑doc | 自动生成 HTML/Markdown 文档。 |
protoc --decode_raw | “盲拆”调试二进制,快速定位字段。 |
8. 常踩的坑 + FAQ
- 64 bit 整数在 JS 会丢精度?
Protobuf‑JSON 映射会把int64/uint64
转成字符串返回,保持精度。 - 字段顺序能随便调吗?
能,只影响字节大小,不影响兼容;Tag 才是硬指标。 - 大包 (>4 MiB) gRPC 传不动?
调服务器grpc.max_receive_message_length
或改流式 RPC。 - 反射 API 很慢?
生产环境少用;必要时切 Lite runtime + 手写访问器。
9. 与 JSON / FlatBuffers / Thrift 对比
方案 | 体积 | 编解码 | 读时 0 拷贝 | 演进友好 | 主要场景 |
---|---|---|---|---|---|
Protobuf | ★★★★ | ★★★★ | ❌ | ★★★★ | RPC、事件流 |
JSON | ★★ | ★★ | ❌ | ★★★ | 调试、人机交互 |
FlatBuffers | ★★★★★ | ★★★★ | ✅ | ★★★ | 移动游戏、MMAP |
Cap’n Proto | ★★★★★ | ★★★★★ | ✅ | ★★★ | IPC、嵌入式 |
Thrift | ★★★★ | ★★★ | ❌ | ★★★ | 老系统、金融行业 |
10. 结语:把 .proto 当成“团队契约”
- 字段编号 = 合同条款号,定下来就别改。
- 类型定义 = 条款内容,变动必须所有微服务一起升级。
- protoc = 自动翻译官,让 C++/Java/Python 都读同一本合同。
相关文章:
Protocol Buffers 全流程通俗讲解
Protocol Buffers 全流程通俗讲解(从 0 到进阶) 目录 序列化到底为什么要选 Protobuf?核心原理:一眼看懂二进制编码10 分钟跑通「写 .proto → 生成代码 → 读写数据」.proto 文件 8 条黄金法则(小白友好版&…...
从故障到防护:抗晃电保护装置如何提升电网可靠性?
安科瑞刘鸿鹏 摘要 随着工业自动化水平的提升,生产设备对供电连续性和稳定性的依赖程度越来越高,电网中的电压暂降(俗称“晃电”)问题对工业生产构成了严重威胁。特别是在化工、冶金、半导体等高敏感行业,晃电引发的…...
Three.js知识框架
一、Three.js 基础概念 1. Three.js 简介 是什么? 基于 WebGL 的 3D JavaScript 库,用于在浏览器中渲染 3D 场景。 核心优势 简化 WebGL 的复杂 API,提供高层封装。 跨平台(支持桌面和移动端)。 适用场景 3D 可视…...
5.14本日总结
一、英语 背诵list30,复习list1 二、数学 完成30讲第13讲课后题,学习14讲部分内容 三、408 完成计网5.1,5.2题目 四、总结 在高数14讲内容学完之前写完13讲的所有题目,预计20号学完14讲内容,408的进度要加快,本…...
数据结构学习之链表学习:单链表
在之前顺序表的学习过程中,我们知道顺序表中头插和中插的复杂度是O(N)。那我们可不可以将其降低为O(1)呢?可不可以不增容想用就用想扔就扔而不会浪费一点空间呢?那就是我们今天的内容࿱…...
技术债务积累,如何进行有效管理
识别和评估技术债务、明确技术债务的优先级、制定系统的还债计划、持续监控与预防技术债务产生是有效管理技术债务积累的重要策略。其中尤其要注重识别和评估技术债务,只有准确识别技术债务的种类和严重程度,才能制定出高效且有针对性的解决方案…...
[20250514] 脑机接口行业调研报告(2024年最新版)
脑机接口行业调研报告(2024年最新版) 1. 调研报告 2. 相关企业...
【HTTPS基础概念与原理】SSL/TLS协议演进史:从SSLv3到TLS 1.3
以下是 SSL/TLS协议演进史 的详细解析,从SSLv3到TLS 1.3,涵盖各版本的核心特点、重大漏洞及淘汰原因: 1. SSLv3(Secure Sockets Layer 3.0) • 发布时间:1996年(Netscape开发) • 核…...
JVM 与云原生的完美融合:引领技术潮流
最近佳作推荐: Java 大厂面试题 – 揭秘 JVM 底层原理:那些令人疯狂的技术真相(New) Java 大厂面试题 – JVM 性能优化终极指南:从入门到精通的技术盛宴(New) Java 大厂面试题 – JVM 深度剖析&…...
【进程控制二】进程替换和bash解释器
【进程控制二】进程替换 1.exec系列接口2.execl系列2.1execl接口2.2execlp接口2.3execle 3.execv系列3.1execv3.2总结 4.实现一个bash解释器4.1内建命令 通过fork创建的子进程,会继承父进程的代码和数据,因此本质上还是在执行父进程的代码 进程替换可以将…...
如何查看打开的 git bash 窗口是否是管理员权限打开
在 git bash 中输入: net session >nul 2>&1 && (echo Ok) || (echo Failed) 显示 OK 》是管理员权限; 显示 Failed 》不是管理员权限。 如何删除此步生成的垃圾文件: 新建一个 .txt 文件,输入以下代码…...
ubuntu 22.04 wifi网卡配置地址上网
通过network-manager配置 确定是否存在usb网卡的驱动 rootgpu-server:/etc/netplan# lsmod | grep rt2800usbrt2800usb 32768 0rt2x00usb 24576 1 rt2800usbrt2800lib 139264 1 rt2800usbrt2x00lib 73728 3 rt2800us…...
让 Cursor 教我写 MCP Client
文章目录 1. 写在最前面2. 动手实现一个 MCP Client2.1 How 天气查询 Client2.1.1 向 Cursor 提问的艺术2.1.2 最终成功展示2.1.3 client 的代码 3. MCP 协议核心之一总结3.1 SSE vs WebSocket 4. 碎碎念5. 参考资料 1. 写在最前面 学习了 MCP Server 的实现后,刚好…...
GoogleTest:GMock2 EXPECT_CALL
GoogleTest:GMock初识-CSDN博客 简单的介绍了GMock工作的方式 GMock其实是比较复杂的,先上一个例子,然后再仔细的解读: //not_ready_class.hpp #include <string>class Person { public:virtual ~Person() = default;virtual std::string name() = 0;virtual int a…...
自注意力机制(Self-Attention)前向传播手撕
题目 实现Transformer中自注意力机制的前向传播代码 思路与代码 自注意力机制(Self-Attention)是自然语言处理和深度学习中的一种核心机制,最早在 Transformer 模型中被提出。它的核心思想是:让序列中的每个元素都能动态关注整个…...
华硕服务器-品类介绍
目录 一、核心产品线解析 1. 机架式服务器 2. 塔式服务器 3. 高密度计算服务器 二、关键技术与模组配置 1. 主板与管理模块 2. 电源与散热 3. 存储与网络 三、应用场景与行业解决方案 1. 人工智能与高性能计算 2. 云计算与虚拟化 3. 边缘计算与工业物联网 一、核心…...
【Ansible基础】Ansible设计理念与无代理架构深度解析
目录 1 Ansible概述与核心设计理念 1.1 Ansible的核心设计哲学 1.2 Ansible与其他配置管理工具的对比 2 Ansible无代理架构详解 2.1 无代理架构工作原理 2.2 无代理架构的优势 2.3 无代理架构的局限性 3 Ansible核心组件与架构 3.1 Ansible核心组件架构 组件说明&…...
利用vba替换word中多个表格,相邻单元格的文字
目录 一、效果图1、替换前2、替换后 二、敲代码1、开发者工具→vba编辑器,点击插入模块2、键入以下代码3、代码编辑完成后,开发者工具→运行宏,选择对应名称,运行 一、效果图 标题估计没说明白,上图 1、替换前 2、替…...
动态多因子策略
策略其核心思想是通过多种技术指标的结合,动态调整交易信号,以实现更精准的市场进出和风险管理。 交易逻辑思路 1. 初始化与数据更新: - 在每个Bar的开盘时,更新当日的最高价、最低价和收盘价。 - 计算短期和长期的移动平均线&…...
STC32G12K128实战:串口通信
STC32G12K128芯片写一个按键通过串口1发送字符串的程序。首先,确认芯片的串口1配置。STC32G系列通常使用UART1,相关的寄存器是P_SW1来选择引脚。默认情况下,UART1的TX是P3.1。 接下来是设置定时器作为波特率发生器。通常用定时器2,…...
基于javaweb的SpringBoot高校图书馆座位预约系统设计与实现(源码+文档+部署讲解)
技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...
一种资源有限单片机处理cJSON数据的方法
一般单片机处理cJSON格式的数据都直接使用cJSON库,但对于Ram较小的单片机,由于资源有限,这并不合适,但我们可以根据cJSON数据的特定格式,使用土方法,直接对字符进行查找裁剪即可 //截取字符串str中字符a与…...
【2025版】Spring Boot面试题
文章目录 1. Spring, Spring MVC, SpringBoot是什么关系?2. 谈一谈对Spring IoC的理解3. Component 和 Bean 的区别?4. Autowired 和 Resource 的区别?5. 注入Bean的方法有哪些?6. 为什么Spring 官方推荐构造函数注入?…...
C++——类和对象(1)
文章目录 一、前言二、类和对象上2.1 类的定义2.1.1 定义格式一2.1.2 定义格式二2.1.3 注意点 2.2 访问限定符2.2.1 访问限定符的用法 2.3 类域2.4 类的实例化2.4.1 实例化的概念2.4.2 实例化具体举例2.4.3类的实例化对象大小 2.5 this指针2.5.1 this指针的概念2.5.6 this指针的…...
【行为型之观察者模式】游戏开发实战——Unity事件驱动架构的核心实现策略
文章目录 🎯 观察者模式(Observer Pattern)深度解析一、模式本质与核心价值二、经典UML结构三、Unity实战代码(玩家血量监控系统)1. 定义观察者接口与主题基类2. 实现具体主题(玩家血量)3. 实现…...
Java基础语法之数组
数组 一、认识数组 1.什么是数组 数组就是一个容器,用来存一批同种类型的数据。 举例 20, 10, 80, 60, 90 int[] arr {20, 10, 80, 60, 90};张三, 李四, 王五 String[] names {"张三", "李四", "王五"};2.为什么要使用数组 假设…...
Vue3学习(组合式API——计算属性computed详解)
目录 一、计算属性computed。 Vue官方提供的案例。(普通写法与计算属性写法) 使用计算属性computed重构——>简化描述响应式状态的复杂逻辑。 (1)计算属性computed小案例。 <1>需求说明。(筛选原数组——>得新数组) &…...
高海拔和远距离的人员识别:面部、体型和步态的融合
大家读完就觉得有帮助记得关注和点赞!!! 摘要 我们解决了在无约束环境中进行全身人体识别的问题。这个问题出现在诸如IARPA高空和远距离生物识别与身份识别(BRIAR)计划等监视场景中,其中生物识别数据是在长…...
《P2345 [USACO04OPEN] MooFest G》
题目背景 P5094 [USACO04OPEN] MooFest G 加强版 题目描述 约翰的 n 头奶牛每年都会参加“哞哞大会”。 哞哞大会是奶牛界的盛事。集会上的活动很多,比如堆干草,跨栅栏,摸牛仔的屁股等等。 它们参加活动时会聚在一起,第 i 头…...
浅浅学:DoIP工作流程及基于DoIP的诊断/刷写工具
注:阅读本文需要对UDS及BootLoader有一定了解,基础内容不做赘述。 在汽车"新四化"浪潮的推动下,智能座舱、自动驾驶、车路协同等创新技术正加速重构行业格局。随着车载ECU数量突破百个量级,软件代码量呈指数级增长——…...
首个专业AI设计Agent发布-Lovart
Lovart是什么 Lovart 是为设计师打造的世界上首个专业设计 Agent。Lovart 能像专业设计师一样思考和执行设计任务,提供高水平的设计方案。基于自然语言交互,用户能快速调整布局、颜色和构图。Lovart 支持从创意拆解到专业交付的全链路设计,单…...
二叉树(中序遍历)
嘿,欢迎来到小巫blog!小巫又来啦!看到你对二叉树中序遍历这道题有点困惑,别担心,我会一步步带你搞定它!这道题是树的基础题目,掌握了它,你对树的遍历就会有很深的理解。我相信&#…...
Ubuntu 系统默认已安装 python,此处只需添加一个超链接即可
步骤 1:确认 Python 3 的安装路径 查看当前 Python 3 的路径: which python3 输出类似: /usr/bin/python3 步骤 2:创建符号链接 使用 ln -s 创建符号链接,将 python 指向 python3: sudo ln -s /usr/b…...
AcroForm JavaScript Promise 对象应用示例: 异步加载PDF文件
这段代码演示了在Adobe Acrobat DC Pro 的 JavaScript 环境中如何使用 Promise 对象处理异步操作。具体功能是: 定义了一个loadFile函数,模拟异步加载PDF文件的操作使用Promise对象封装异步操作,提供成功(resolve)和失败(reject)两种状态通过…...
LeetCode 热题 100 114. 二叉树展开为链表
LeetCode 热题 100 | 114. 二叉树展开为链表 大家好,今天我们来解决一道经典的二叉树问题——二叉树展开为链表。这道题在 LeetCode 上被标记为中等难度,要求将二叉树展开为一个单链表,展开后的单链表应该与二叉树的先序遍历顺序相同。 问题…...
DML和DQL
1. 设置MySQL的储存引擎 上一章的附录里已经将ini设置好了,不用再次设置 2. DML语句 插入单数据记录 插入多数据记录 将查询结果插入新表 更新数据 删除数据 注意:delete删除只会删除数据,不会重置表的现有逻辑,truncate会重置表逻…...
多线程与线程互斥
我们初步学习完线程之后,就要来试着写一写多线程了。在写之前,我们需要继续来学习一个线程接口——叫做线程分离。 默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法…...
BMS工具箱用来执行贝叶斯模型平均(BMA)计算模块
贝叶斯模型平均(Bayesian Model Averaging,BMA)是一种用于处理模型不确定性的统计方法,通过结合多个模型的预测结果来提高预测的准确性和鲁棒性。在 MATLAB 中,可以使用专门的工具箱(如 BMS 工具箱…...
Java死锁排查:线上救火实战指南
想象一下,你正在值班,突然监控告警红成一片,用户反馈雪花般飘来:“系统卡死了!用不了了!” —— 这很可能就是Java应用遭遇了“死锁”这个大魔王。这时候,你就是救火队长,首要任务不…...
第十九次博客打卡
今天学习的内容是Java中的常见循环。 在 Java 中,常见的循环结构主要有以下几种:for 循环、while 循环、do-while 循环以及增强型 for 循环(也称为 for-each 循环)。 1. for 循环 for 循环是一种非常灵活的循环结构,…...
智能体制作学习笔记1——智能体
01 智能体_哔哩哔哩_bilibili 大语言模型可以理解成一个很厉害的人。 但是要完成一些特定的工作,除了大语言模型,还需要一些工具和业务流程,这样才能自动化帮我们完成特定的工作,这个就叫做智能体。 突然发现放视频的时候出现了…...
Python常见问题
文章目录 1.python有哪些数据类型2.python中的元组和列表的区别是什么?3.python中的break、continue、pass代表什么意思?4.如何在python中生成一个随机数?5.Python有哪些常见的内置函数?6.请用自己最擅长的编程语言,将…...
小程序 存存上下滑动的页面
推荐阅读文档: Vue3组合式API之getCurrentInstance详解 - 且行且思 - 博客园Vue2中,可以通过this来获取当前组件实例; Vue3中,在setup中无法通过this获取组件实例,console.log(this)打印出来的值是undefined。 在Vue3…...
更换git位置并在pycharm中重新配置
更新 PyCharm 中的 Git 路径 更新 PyCharm 终端的 Shell 路径 检查环境变量 确保系统环境变量中的 Path 包含了新的 Git 安装路径 ,如果使用unins0000自动卸载就不会有旧路径。...
AI世界的崩塌:当人类思考枯竭引发数据生态链断裂
AI世界的崩塌:当人类思考枯竭引发数据生态链断裂 ——论过度依赖AI创作对技术进化的反噬 一、数据生态的恶性循环:AI的“自噬危机” 当前AI模型的训练依赖于人类创造的原始数据——书籍、论文、艺术作品、社交媒体动态等。据统计,2025年全球…...
OkHttp连接池
🧰 调整连接池的核心参数 ✅ 最大空闲连接数(maxIdleConnections): 含义:连接池中最多保留的空闲连接数量。默认值:5建议值:10~50(视并发量而定) ✅ 连接保持时间&…...
哈希表的实现01
文章目录 哈希表的实现01哈希概念直接定址法哈希冲突负载因子将关键字转换为整数 哈希函数除法散列法:乘法散列法(了解)全域散列法(了解) 处理哈希冲突(开放定址法)线性探测:二次探测…...
学习日志06 java
还有四天要去比赛了,能赢吗?逼自己一把。。。!!加油! 1 对比一下java重写还是不重写tostring的区别 1. 不重写 toString() 的情况 java class Point {private int x;private int y;public Point(int x, int y) {th…...
spring中的@MapperScan注解详解
一、核心功能与作用 MapperScan是Spring与MyBatis框架集成时用于批量扫描Mapper接口的核心注解,其主要功能包括: 自动注册Mapper接口 通过指定包路径,Spring会自动扫描该路径下的所有Mapper接口,并将其注册为Spring Bean&#x…...
PYTHON训练营DAY25
BUG与报错 一、try else try:# 可能会引发异常的代码 except ExceptionType: # 最好指定具体的异常类型,例如 ZeroDivisionError, FileNotFoundError# 当 try 块中发生 ExceptionType 类型的异常时执行的代码 except: # 不推荐:捕获所有类型的异常&…...