
HoRain云小助手个人主页 个人专栏: 《Linux 系列教程》《c语言教程》⛺️生活的理想就是为了理想的生活!⛳️ 推荐前些天发现了一个超棒的服务器购买网站性价比超高大内存超划算忍不住分享一下给大家。点击跳转到网站。专栏介绍专栏名称专栏介绍《C语言》本专栏主要撰写C干货内容和编程技巧让大家从底层了解C把更多的知识由抽象到简单通俗易懂。《网络协议》本专栏主要是注重从底层来给大家一步步剖析网络协议的奥秘一起解密网络协议在运行中协议的基本运行机制《docker容器精解篇》全面深入解析 docker 容器从基础到进阶涵盖原理、操作、实践案例助您精通 docker。《linux系列》本专栏主要撰写Linux干货内容从基础到进阶知识由抽象到简单通俗易懂帮你从新手小白到扫地僧。《python 系列》本专栏着重撰写Python相关的干货内容与编程技巧助力大家从底层去认识Python将更多复杂的知识由抽象转化为简单易懂的内容。《试题库》本专栏主要是发布一些考试和练习题库涵盖软考、HCIE、HRCE、CCNA等目录⛳️ 推荐专栏介绍一、JDK 原生序列化怎么用serialVersionUID版本控制的命门想更细粒度控制二、为什么企业级项目基本不用原生序列化三、替代方案怎么选四、面试几句能加分的话Java 序列化说白了就是把内存里的对象转成字节流序列化或者把字节流还原成对象反序列化用来做持久化、网络传输、RPC、缓存存储、深拷贝这些事。JDK 自带了一套基于Serializable的机制但实际生产里已经很少裸用了——下面把怎么用 坑在哪 用什么替代一次讲清。一、JDK 原生序列化怎么用核心就三样Serializable标记接口、ObjectOutputStream/ObjectInputStream、再加两个关键字transient和serialVersionUID。class User implements Serializable { private static final long serialVersionUID 1L; private String name; private int age; private transient String password; // 不参与序列化 }序列化 / 反序列化// 序列化 try (ObjectOutputStream oos new ObjectOutputStream( new FileOutputStream(user.dat))) { oos.writeObject(user); } // 反序列化 try (ObjectInputStream ois new ObjectInputStream( new FileInputStream(user.dat))) { User u (User) ois.readObject(); }几个关键点Serializable是标记接口没有任何方法只告诉 JVM这个类可以序列化否则抛NotSerializableExceptiontransient 修饰的字段会被跳过反序列化后是默认值null/0常用于密码、临时缓存、派生字段静态字段不会被序列化——它属于类不属于对象父类实现Serializable子类自动可序列化反过来不行serialVersionUID版本控制的命门如果不手动声明JVM 会根据类名、字段、方法等算一个哈希值。只要类结构稍微一动加个字段、改个方法哈希就变旧字节流在新类上反序列化直接InvalidClassException。private static final long serialVersionUID 1L; // 手动写死结构兼容就不改 规则只有破坏性变更旧数据真的不该再反序列化才改 UID加字段、改注释这种兼容改动不用动它。想更细粒度控制writeObject/readObject在类里私有限定这两个方法JVM 会回调里面先调defaultWriteObject()处理非 transient 字段再自己加逻辑比如重建 transient 派生值、做校验readResolve()反序列化完返回哪个对象你说了算单例保护神器防止反序列化搞出第二个实例ExternalizableSerializable的子接口自己实现writeExternal/readExternal完全掌控字节格式但样板代码多二、为什么企业级项目基本不用原生序列化这块是面试高频也是新手最容易只背概念、不理解后果的地方问题说明反序列化漏洞RCE反序列化不只是读数据还会触发对象重建逻辑如readObject、hashCode。攻击者可以构造恶意字节流利用 Commons Collections 这类库的 gadget chain 在反序列化时执行任意代码。WebLogic、JBoss 当年中招的都是这个性能差基于反射字节流里塞了大量类元数据类名、包名、父类…体积大、CPU 高比 Protobuf/Kryo 慢一个量级跨语言不行只有 JVM 认得Go/Python/C 解析不了分布式多语言场景直接出局版本脆弱类结构一变就容易炸微服务各自部署节奏不一致就是灾难可读性为零二进制类信息线上排查基本靠猜还有个容易被忽略的点反序列化还能导致 OOM——恶意构造的对象图循环引用、超大 Map、gadget chain 无限递归能把堆吃完。⚠️ 所以现在的共识是不可信来源的字节流绝对不要直接ObjectInputStream.readObject()。如果一定要用至少做白名单ObjectInputFilter、限大小、验来源。三、替代方案怎么选原生序列化基本只在纯 Java 简单本地持久化 不在乎跨语言这种窄场景才用。主流替代JSONJackson / Gson / FastJSON文本、可读、跨语言、生态最广慢一点、体积大但系统边界HTTP API、对外接口首选注意 FastJSON 老版本有漏洞要跟到新版本ProtobufGoogle二进制、体积小、快、跨语言、schema 演进友好要写.protogRPC 默认搭档分布式 RPC、跨语言服务间通信首选Hessian二进制、跨语言、Dubbo 早期默认比原生快但不如 Protobuf 极致Kryo纯 Java 里最快最小的之一Spark / Flink 在用不跨语言版本兼容也比 Protobuf 弱游戏、纯 Java 低延迟 RPC、缓存Redis 存 Java 对象合适AvroSchema Registry 那套事件流 / 数据管道演进强Kafka 场景多见速记选型HTTP 接口 / 对外 API → JSON跨语言 RPC → Protobuf或 Thrift纯 Java 高性能 / 缓存 → Kryo事件流管道 → Avro四、面试几句能加分的话序列化不走静态字段、transient才是排除字段的正解serialVersionUID不手写 JVM 按类结构算类一改旧数据全废单例要加readResolve()否则反序列化会新建实例原生序列化最大的问题不是性能是反序列化 RCE生产禁用或严加过滤选型先看边界是不是跨语言 / 要不要演进再看性能如果想再往下挖可以聊ObjectInputFilter怎么配白名单、Protobuf 的 proto2 vs proto3 差异或者Kryo 为什么线程不安全——挑一个❤️❤️❤️本人水平有限如有纰漏欢迎各位大佬评论批评指正如果觉得这篇文对你有帮助的话也请给个点赞、收藏下吧非常感谢! Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧