Serializable探究一二

序列化探究一二

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对象序列化成功!");
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值