序列化——谨慎实现Serializable
admin
2024-05-08 22:22:55
0

何为序列化

序列化与反序列化对应。

序列化:将一个对象转为字节流

反序列化: 将字节流转为对象

通过序列化继续,可以将对象编码之后,通过网络传输到其他应用中,再反序列化,实现远程交互调用。


如何序列化

要想使一个类的实例可以实例化,只需要实现 Serializable 即可。

正因为实现序列化太简单,很容易给程序员一种误解:序列化很容易,不需要考虑太多。

实际的情形却比较复杂。

标记类可实例化很简单,执行实例化动作的直接开销也很低。


序列化实例

我们先创建一个Car类

@Data
@Accessors(chain = true)
public class Car implements Serializable {private static final Long serialVersionUID = 1L;private String id;private Integer age;private String name;
}

创建序列化和反序列化方法

public class Client {public static void main(String[] args) throws Exception {
//        ser();dser();}/*** 序列化* @throws Exception*/static void ser() throws Exception {//age会序列化默认值nullCar car = new Car().setId("13").setName("小红");FileOutputStream fileOut =new FileOutputStream("C:\\Users\\admin\\Desktop\\file_upload\\car.ser");ObjectOutputStream out = new ObjectOutputStream(fileOut);out.writeObject(car);out.close();fileOut.close();System.out.println("--------序列化完成----------");}/*** 反序列化* @throws Exception*/static void dser() throws Exception {FileInputStream fileIn = new FileInputStream("C:\\Users\\admin\\Desktop\\file_upload\\car.ser");ObjectInputStream in = new ObjectInputStream(fileIn);Car car = (Car) in.readObject();in.close();fileIn.close();System.out.println("---------反序列化完成-------");System.out.println(car);}

如果需要特殊定制序列化, 这种情况,只有指定的字段被处理,其他的字段丢失。 注意,读写的顺序对应,否则值就串了

我们在Car类添加两个方法

@Data
@Accessors(chain = true)
public class Car implements Serializable {private static final Long serialVersionUID = 1L;private String id;private Integer age;private String name;private void writeObject(ObjectOutputStream out) throws IOException {System.out.println("writeObject");out.writeObject(id);out.writeInt(age == null? 1:age);out.writeObject(name);}private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {System.out.println("readObject");this.id= in.readObject().toString();this.age = in.readInt();this.name =in.readObject().toString();}
}

序列化的代价

1、一旦确认了序列化的形式。后续任何变动,都可能导致使用这个格式进行反序列化的程序发生错误。

2、默认的序列化会导出私有字段这一点与封装特性相违背

程序不同版本之间,因为优化或者修复 bug ,改变内部的私有字段非常常见

这些本来应该被隐藏在具体实现中,调用者不需要也不应该关心,但默认的序列化会导出这些数据

3、序列化是另一种创建对象实例的机制(clone同样也是绕过了构造器)

因为序列化绕过了构造器很容易发生“在构造器中做了安全前提检查,但因为序列化根本不走构造器,所以绕过了这种安全检查”


自定义序列化形式

假设,有个类 Cat 实现了序列化,并且将数据序列化,保存到硬盘或某个位置

之后,Cat 考虑应该继承一个 Animal 父类。并且,Animal 的信息自然也应该属于序列化的一部分

但注意:我们序列化的时候可没有保存 Animal 信息

这时候怎么办?

java 给出的方案就是 readObjectNoData

也就是,没有流,给一个默认的恢复方案。java 会调用 Animal 的 readObjectNoData

当然,还有一种类似的情况。就是本来就继承 Animal ,但Animal 忘了声明序列化。

在保存数据之后想起来了,加上了 Serializable ,但因为之前的数据中也没有 序列化父类信息

所以恢复的时候也应该从 readObjectNoData设置

总结: 此方法用在序列化的父类中。当子类序列化时候,父类未参与。

但后续反序列化的时候根据新规则,父类需要参与反序列化,可实际信息中,父类并没有,所以,需要用 readObjectNoData

回到刚才的话题,为什么需要书写 readObjectNoData?

因为,如果我们去掉这个方法,父类就默认不处理数据了,这时候可能处于错误的状态中

当然,如果父类不面临这种问题,就不需要处理

例子:

假设现在Car需要继承Animal

@Data
@Accessors(chain = true)
public class Animal{public int pid;
}
@Data
@Accessors(chain = true)
public class Car extends Animal implements Serializable {private static final Long serialVersionUID = 1L;private String id;private Integer age;private String name;private void writeObject(ObjectOutputStream out) throws IOException {System.out.println("writeObject");out.writeObject(id);out.writeInt(age == null? 1:age);out.writeObject(name);}private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {System.out.println("readObject");this.id= in.readObject().toString();this.age = in.readInt();this.name =in.readObject().toString();}
}

由于之前序列化的时候没有继承Animal,所以反序列化的时候,获取Animal的字段均为默认值,这个时候如果要自定义给Animal赋值就需要这样做

@Data
@Accessors(chain = true)
public class Animal implements Serializable {private static final Long serialVersionUID = 1L;public int pid;private void readObjectNoData() throws IOException, ClassNotFoundException {System.out.println("readObjectNoData");this.pid = 1;}
}

我们给父类的pid赋值1 ,然后调用反序列化方法

public class Client {public static void main(String[] args) throws Exception {
//        ser();dser();}/*** 序列化* @throws Exception*/static void ser() throws Exception {//age会序列化默认值nullCar car = new Car().setId("13").setName("小红");FileOutputStream fileOut =new FileOutputStream("C:\\Users\\admin\\Desktop\\file_upload\\car.ser");ObjectOutputStream out = new ObjectOutputStream(fileOut);out.writeObject(car);out.close();fileOut.close();System.out.println("--------序列化完成----------");}/*** 反序列化* @throws Exception*/static void dser() throws Exception {FileInputStream fileIn = new FileInputStream("C:\\Users\\admin\\Desktop\\file_upload\\car.ser");ObjectInputStream in = new ObjectInputStream(fileIn);Car car = (Car) in.readObject();in.close();fileIn.close();System.out.println("---------反序列化完成-------");System.out.println(car);System.out.println(car.pid);}
}

可以看到,父类的pid字段被成功赋值 

readObjectNoData
readObject
---------反序列化完成-------
Car(id=13, age=1, name=小红)


补充说明

以上的情况是出于谨慎考虑,实际上, 现在很多框架都不会明确依赖序列化

更多的是Object - json 的路线或者使用 rest api

现在的 SpringBoot 或 SpringCloud 项目,一般不会被序列化问题所困扰

相关内容

热门资讯

皇姑核芯的“低密答案”:TA,... 2026年的沈阳楼市,正走过一个微妙的分水岭,楼市进入分化阶段已经成为行业共识。 数据释放的信号很明...
德国金属材料产业链调整:中国园... (来源:欧洲并购与投资) 德国金属材料产业链调整:中国园区该承接什么、不该承接什么 本系列前两篇分...
消费医药新基金快速建仓 洼地资... 来源:21世纪经济报道 证券时报记者 安仲文 今年上半年,全市场200多只科技主题基金净值翻倍,这...
原创 7... 深夜,港交所的审核员桌上,摆着一份举报材料。 举报人叫陈浩,小红书前华南商业化负责人。 他手里攥着一...
原创 7... 2026年上半年,国际油价经历了一轮惊心动魄的“过山车”。2月28日美以伊战事爆发后,霍尔木兹海峡航...
7月6日盘前停复牌汇总 7月6日,动力源临停;好利科技、阿科力复牌。 上证报中国证券网讯 7月6日,1家公司临停:动力源;2...
股市必读:江阴银行(00280... 截至2026年7月3日收盘,江阴银行(002807)报收于3.85元,上涨0.52%,换手率0.7%...
原创 拼... 最近,拼多多在雄安买楼了,一整栋,12层,7月底就要投用。 这件事,乍一看是个商业地产新闻,往深了想...
突破“高龄禁区” 绿色通道助百... 本报讯(记者 张 琦 通讯员 冯金灿)“特别感谢河南省第三人民医院(河南省职业病医院)骨科和麻醉科的...
原创 A... 除了A股交易新规落地之外,A股再融资新规又一次吸引了市场的目光。虽然7月3日发布的再融资新规仍然是征...
獐子岛董事会聘任57岁汪国栋为... 7月4日,獐子岛(002069)发布第九届董事会第九次会议决议公告,董事会同意聘任汪国栋为公司副总裁...
上市不到4个月出手,飞速创新拟... 飞速创新(03355.HK)7月5日公告,公司拟3.3亿元收购上海博达数据通信100%股权。 据公告...
怎么回收金项链 南昌本地黄金回... 近年来,随着黄金价格波动,不少持有闲置黄金制品的用户会产生变现需求,其中回收金项链是较为常见的用户需...
两仓同开叮咚买菜进驻淮安 升级... 7月5日,主打“在线菜篮子”的生鲜电商叮咚买菜淮安楚州站、府苑站双站同步开仓运营,标志着叮咚买菜正式...
防范美股泡沫爆破带来的风险外溢 我们先来梳理全球市场,判断哪些市场走势具备前瞻参考价值。 第一是恒生指数,第二是恒生科技指数,这两大...
央视曝光黄金回收“作弊秤”!一... 有消费者投诉在黄金回收交易中遭遇了“违规秤”,造成了不小的经济损失。记者了解到,眼下市场上售价利润最...
单仁:字节全员信背后,AI正在... 01 最近这几天,字节跳动CEO梁汝波的全员信,引起了很多企业家的关注。 表面上看,这只是一个大厂时...
2026麻涌镇企业短视频制作:... 麻涌镇企业短视频制作是以本地制造业与服务业诉求的内容生产与平台运营服务,2026年,这一行业的竞争核...
4nm近售罄、部分8nm接近满... 《科创板日报》7月4日讯据朝鲜日报报道,业内人士称,随着AI半导体需求升温、全球大型科技公司订单增加...