java反序列化入门_Java序列化与反序列化入门理解

一、序列化与反序列化的概念以及使用场景

1、概念

a)序列化:将对象转换成字节序列的过程;

b)反序列化:将字节序列恢复成对象的过程。

2、使用场景

1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;

2) 在网络上传送对象的字节序列。

二、结合例子说明

进行序列化的对象,需要实现Serializable接口,否则将无法序列化。序列化采用ObjectOutputStream的writeObject方法实现;反序列化则使用ObjectInputStream的readObject将字节序列还原成对象。

首先创建一个User类,只有简单的几个属性,如下:

import java.io.Serializable;

public class User implements Serializable {

private String name;

private int age;

private String address;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String getAddress() {

return address;

}

public void setAddress(String address) {

this.address = address;

}

@Override

public String toString() {

//重写了toString,方便打印观察

return "age:"+age+",name:"+name+",address:"+address;

}

}

User对象已经实现了序列化接口。接着进行测试,如下:

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

public class Test {

/**

* 序列化

* @param filePath

* 序列化要写入的文件路径

* @throws Exception

*/

public static void writeObject(String filePath)throws Exception{

User u = new User();

u.setAddress("福建省厦门市");

u.setAge(18);

u.setName("漫天的沙");

ObjectOutputStream oos = null;

try{

oos = new ObjectOutputStream(new FileOutputStream(filePath));

oos.writeObject(u);

oos.flush();

}finally{

if(oos != null){

oos.close();

}

}

}

/**

* 反序列化

* @param filePath

* 序列化的文件

* @throws Exception

*/

public static void readObject(String filePath) throws Exception{

ObjectInputStream ois = null;

try{

ois = new ObjectInputStream(new FileInputStream(filePath));

User u = (User)ois.readObject();

System.out.println(u);

}finally{

if(ois != null){

ois.close();

}

}

}

public static void main(String[] args) throws Exception{

String filePath = "f:/obj.out";

writeObject(filePath);

readObject(filePath);

}

}

执行后打印如下:

593c2c1dc9c8add7afe689881a33dab2.png

证明反序列化成功。

三、扩展

1、serialVersionUID

实现了Serializable接口的对象,如果没有显性的设置serialVersionUID,系统会自动根据方法/属性等计算序列化ID,如果显性进行了设置,则直接使用该值。serialVersionUID有什么用呢?我们可以试着对User对象进行显性设置serialVersionUID=1L,然后再将之前序列化的文件进行反序列化,如下:

/** 为用户对象显性设置序列化id */

private static final long serialVersionUID = 1L;

重新运行程序,报错如下:

Exception in thread "main" java.io.InvalidClassException: User; local class incompatible: stream classdesc serialVersionUID = -5216935088914625952, local class serialVersionUID = 1

at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)

at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1583)

at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)

at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)

at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)

at Test.readObject(Test.java:42)

at Test.main(Test.java:54)

意思即序列化文件的序列化ID与要反序列化成的对象序列化ID不兼容,因此反序列化失败。所以,如果序列化对象后续可能会增减字段或者修改,为了保证兼容,需要显性的设置序列化ID,避免修改之后原先的序列化不能成功的反序列化产生问题。

2、transient字段使用

如果字段不需要进行序列化,可以在修饰符后添加transient的声明,这样在序列化的时候属性将不参与序列化,例如上面的User对象name不参与序列化,则声明为

/** transient在对象初始化时可以让该字段不参与序列化 */

private transient String name;

重新运行程序,如下:

age:18,name:null,address:福建省厦门市

3、静态变量序列化

正常情况下,静态变量也可以正常的序列化。但是如果中间静态变量进行调整呢,序列化的对象中该静态变量是否会产生变化?为了验证效果,在上面的User新增一个静态变量,同时为了方便观察,重写toString方法,如下:

/**User对象新增的静态变量*/

public static int a = 35555;

@Override

public String toString() {

//重写了toString,方便打印观察

return "age:"+age+",name:"+name+",address:"+address+",a:"+a;

}

对main方法调整了,如下:

public static void main(String[] args) throws Exception{

String filePath = "f:/obj.out";

writeObject(filePath);

//修改User静态变量a的值

User.a = 10;

readObject(filePath);

}

重新运行,结果如下:

age:18,name:null,address:福建省厦门市,a:10

说明静态变量的值变了。分析原因,因为序列化保存的是对象的状态,静态变量属于类的状态,因此序列化并不保存静态变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值