您的位置:首页 > 编程语言 > Java开发

Serializable探究一二

2016-07-03 16:52 435 查看

序列化探究一二

Serializable原理

seriaVersionUid的作用

自定义序列化及反序列化过程

  磁盘保存文件,进程间数据交互,网络传输数据等都是先将数据转换为字节序列,收到字节序列后再转换为图片,视频或其他文件。

  这一过程就需要序列化和反序列化的支持。Java中序列化是通过==ObjectOutputStream.writeObject()== 方法将Object转为字节序列后写到输出流中。反序列化是通过==ObjectInputStream.readObject()== 将字节序列转为一个对象。

先上代码:

1.定义一个User类,这个类先不继承Serializable

import java.io.Serializable;

public class User implements Serializable{

private int id;
private String name;
private int age;
private boolean sex;

public User(int id,String name,int age,boolean sex){
this.id = id;
this.name = name;
this.age = age;
this.sex = sex;
}

}


2.实现序列化

public static void enSerializable() throws IOException{
FileOutputStream fo = new FileOutputStream(new File("D:/user.txt"));
ObjectOutputStream oo = new ObjectOutputStream(fo);
oo.writeObject(new User(1,"wangliang",22,true));
oo.close();
}


3.反序列化实现

public static void deSerializable() throws IOException, ClassNotFoundException {
FileInputStream fi = new FileInputStream(new File("D:/user.txt"));
ObjectInputStream oi = new ObjectInputStream(fi);
User user = (User)oi.readObject();
System.out.println("User对象反序列化成功!"+user.getName()+user.getAge());

}


运行报错: java.io.NotSerializableException

但是打开user.txt 发现里面已经写入了数据,虽然都是乱码。此时反序列化失败。

修改User类让其继承Serializable,正常序列化和反序列化。

serialVersionUID的作用

主要是为了类的兼容性。

想象一下这种场景:

  昨天将学生类的数据保存到了磁盘上,今天取数据之前要在学生类上多加一个字段,如果没有指定serialVersionUID,会报错,因为编译器认为这两个类不一致了。此时如果加上serialVersionUID可以正常反序列化。

  通常有两种赋值方式,一种是1L,2L这种,另外一种是64位的Hash值,用那种看你,如果想保持向后兼容,就让serialVersionUID一致,否则改成不一样就好了。

自定义序列化及反序列化过程

方法一:若Student类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化

ObjectOutputStream采用默认的序列化方式,对Student对象的非transient的实例变量进行序列化。

ObjcetInputStream采用默认的反序列化方式,对对Student对象的非transient的实例变量进行反序列化。

方法二:若Student类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。

ObjectOutputStream调用Student对象的writeObject(ObjectOutputStream out)的方法进行序列化。

ObjectInputStream会调用Student对象的readObject(ObjectInputStream in)的方法进行反序列化。

方法三:若Student类实现了Externalnalizable接口,且Student类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。

ObjectOutputStream调用Student对象的writeExternal(ObjectOutput out))的方法进行序列化。

ObjectInputStream会调用Student对象的readExternal(ObjectInput in)的方法进行反序列化。

说明:

1.对于方法一:如果某个字段不想进行序列化和发序列化,那么对该字段加transient关键字修饰即可。

2.方法二和方法三都可以控制序列化和反序列化过程。不同的是方法二在readObject()和writeObject()中进行控制,而且这两个方法不一定必须实现;方法三readExternal()和writeExternal()必须实现,同时继承了 Externalizable接口后不会再执行readObject()和writeObject()方法。

3.自定义序列化过程在实际中用到的可能是控制反序列化后对象的字段顺序,以前项目中遇到过用字段来验签,结果每次序列化后字段顺序不一样导致验签不过,这个问题可以通过自定义序列化过程来解决。

* 继承Externalizable接口代码:*

@Override
public void readExternal(ObjectInput arg0) throws IOException, ClassNotFoundException {
// TODO Auto-generated method stub

setAge(arg0.readInt());
setName((String)arg0.readObject());
setId(arg0.readInt());
setSex(arg0.readBoolean());

}

@Override
public void writeExternal(ObjectOutput arg0) throws IOException {
// TODO Auto-generated method stub
arg0.writeInt(getId());
arg0.writeObject(getName());
arg0.writeInt(getAge());
arg0.writeBoolean(isSex());
System.out.println("User对象序列化成功!");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息