序列化——谨慎实现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=小红)
1 


补充说明

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

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

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

相关内容

热门资讯

蜻蜓订购APP贵金属订购非法期...   蜻蜓订购APP以"投资平台"名义对外宣传,主打贵金属期货(订购)交易。该平台一方面强调自身"正规...
悟空订购APP非法期货交易欺骗...   近期,有投资者反映,“悟空订购APP”等平台以白银、贵金属订购为名,宣传所谓“高收益”“低门槛”...
小赢淘金APP期货投资骗局,平...   “小赢淘金”之流,最擅长的就是用“注册送现金”、“充值返券”的糖衣炮弹来引流。别天真地以为那是福...
八方淘金APP非法期货交易欺骗...   警惕!八方生财、每日淘金、小赢淘金、悟空订购、蜻蜓订购、斗金订购等APP均涉嫌非法期货交易!  ...
智易购APP贵金属订购交易骗局...   很多人看到“3元起投”“充值送福利”“操作简单”“随时提现”这类宣传,很容易把智易购APP当成普...
喜玛银庄APP商品订购投资骗局...   喜玛银庄APP白银、铂金“现货订购”骗局警示:无资质平台涉嫌非法期货交易,投资者爆仓后如何维权?...
吉鑫乐享APP炒贵金属订购交易...   近期,多名投资者反映在“吉鑫乐享APP”进行贵金属投资时遭遇严重亏损,甚至血本无归。看似正规的“...
易掘金APP虚假期货投资骗局,...   “易掘金”的APP它打着“高收益、灵活投资”的旗号,宣称通过“商品订购”就能轻松赚钱,吸引了不少...
在大吉订购APP订购交易亏损被...   近期,不少投资者反映在“大吉订购App”上投资白银、铂金等商品遭遇严重亏损。该平台宣称提供现货订...
铂银壹号APP商品订购交易亏损...   许多中小投资者误以为网上的“商品现货订购”是合规合法的理财渠道,殊不知这背后隐藏着巨大的合规风险...
兴鑫淘金APP贵金属订购交易亏...   白银、贵金属或其他商品类投资,除国家批准的正规期货交易场所及持牌期货公司外,市面上大量第三方交易...
铂银掘金APP无资质的违规平台...   铂银掘金等平台的投资者,往往是被“注册送现金”“充值返现券”“首单免亏”等广告话术吸引,进而下载...
八方淘金APP订购交易不合规,...   “八方淘金APP”“铂银掘金APP”“铂银壹号APP”等软件被指以“现货订购”为名,实际采用高杠...
在指尖订购APP订购商品亏损被...   指尖订购APP这类平台,表面是“订购交易”,实则是披着电商外衣的非法期货陷阱。绝大多数投资者被蒙...
在犀贝易购APP做商品订购交易...   市面上打着“现货投资”“贵金属交易”旗号的APP并不少,但真正合规、受监管的平台并不多。犀贝易购...
易达淘金APP虚假商品订购交易...   易达淘金APP存在严重的虚假宣传与违规交易行为。该平台打着“商品订购”的旗号,实则通过不合规的交...
大浪淘金APP白银订购亏损被骗...   大浪淘金APP最隐蔽的套路,在于其完全封闭的内盘交易系统。表面上,它宣称与国际贵金属市场接轨;实...
一品好购APP上订购白银出现亏...   一品好购APP原名“一品订购”,运营方为上海宝智未来信息技术有限公司。近期不少投资者反映在该平台...
九州订购APP贵金属订购投资骗...   九州订购APP正通过抖.音、快手、今日头条等平台大量投放投资广告,用“5元起投”“充值返现”“0...
坚锅淘金APP交易软件并不正规...   当前,市面上大量所谓的“现货商城订购”交易软件,早已偏离了正常的实物商品买卖,演变为高杠杆、高手...