博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java序列化(含transient)
阅读量:6843 次
发布时间:2019-06-26

本文共 4525 字,大约阅读时间需要 15 分钟。

什么是序列化?

我们创建的对象只有在Java虚拟机保持运行时,才会存在于内存中。如果想要超出Java虚拟机的生命周期,就可以将对象序列化,将对象状态转换为字节序列,写入文件(或socket传输),后面使用时再读入文件,读入原始字节并创建一个完全相同的对象。

PS:只有对象的状态会被序列化,类本身或方法都不会被序列化。

三种序列化方式

1、默认机制

需要序列化的对象,实现java.io.Serializable接口即可。

例子:

import java.io.Serializable;import java.util.Date;import java.util.Calendar;public class PersistentTime implements Serializable {    private Date time;    public PersistentTime() {        time = Calendar.getInstance().getTime();    }    public Date getTime() {        return time;    }}import java.io.ObjectOutputStream;import java.io.FileOutputStream;import java.io.IOException;public class FlattenTime {    public static void main(String[] args) {        String filename = "time.ser";        if (args.length > 0) {            filename = args[0];        }        PersistentTime time = new PersistentTime();        FileOutputStream fos = null;        ObjectOutputStream out = null;        try {            fos = new FileOutputStream(filename);            out = new ObjectOutputStream(fos);            out.writeObject(time);            out.close();        } catch (IOException ex) {            ex.printStackTrace();        }    }}import java.io.ObjectInputStream;import java.io.FileInputStream;import java.io.IOException;import java.util.Calendar;public class InflateTime {    public static void main(String[] args) {        String filename = "time.ser";        if (args.length > 0) {            filename = args[0];        }        PersistentTime time = null;        FileInputStream fis = null;        ObjectInputStream in = null;        try {            fis = new FileInputStream(filename);            in = new ObjectInputStream(fis);            time = (PersistentTime) in.readObject();            in.close();        } catch (IOException ex) {            ex.printStackTrace();        } catch (ClassNotFoundException ex) {            ex.printStackTrace();        }        // print out restored time        System.out.println("Flattened time: " + time.getTime());        System.out.println();        // print out the current time        System.out.println("Current time: " + Calendar.getInstance().getTime());    }}
View Code

注意:

1、持久化的对象必现实现Serializable接口或继承的父类实现了。

2、不能(例如系统级别的类Thread、OutPutStream)或不想被序列化的字段必需加transient声明。

transient是字段的修饰符,当一个字段声明为transient时,它就不能被序列化。

transient不能声明方法、类、接口,它们不需要被序列化。

2、自定义默认协议

由于类的构造函数只要在对象创建时候才调用,而反序列化的对象是用readObject创建的,不会再去调构造函数。如果构造函数里有执行某些行为,那么反序列化回来的对象就会丢失这些行为。

解决方法:增加两个方法,在保证序列化的默认行为后,增加自己要的行为。

private void writeObject(ObjectOutputStream out) throws IOException;private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;

例子:

import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class PersistentAnimation implements Serializable, Runnable {        private static final long serialVersionUID = 2850527457134768151L;        transient private Thread animator;    private int animationSpeed;    public PersistentAnimation(int animationSpeed) {        this.animationSpeed = animationSpeed;        startAnimation();    }    public void run() {        while (true) {            // do animation here        }    }    private void writeObject(ObjectOutputStream out) throws IOException {        out.defaultWriteObject();    }    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {        // our "pseudo-constructor"        in.defaultReadObject();        // now we are a "live" object again, so let's run rebuild and start        startAnimation();    }    private void startAnimation() {        animator = new Thread(this);        animator.start();    }}
View Code

同理,如果父类已经实现Serializable接口,子类又不想被序列化,就可以添加这两个内容为空的方法。

3、自定义协议

实现Externalizable接口,复写writeExternal、readExternal两个方法,自己定义序列化协议(例如pdf的存取)。

public void writeExternal(ObjectOutput out) throws IOException;public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;

序列化的陷阱

1、缓存流中的对象,再修改对象状态再写入是无效的。

ObjectOutputStream out = new ObjectOutputStream(...);MyObject obj = new MyObject(); // must be Serializableobj.setState(100);out.writeObject(obj); // saves object with state = 100obj.setState(200);out.writeObject(obj); // does not save new object state 

2、版本控制

当你序列化一个对象存储到文件后,修改类的定义(例如增加个字段),当你反序列化时,会报一个java.io.InvalidClassException的异常。这是因为所有可以持续化的类都会有一个唯一的标识符,如果类的标识符跟反序列化对象的标识符不一样时,就会报这个异常。

解决方法:增加一个serialVersionUID字段作为类的标识符,只要标识符不变,就可反序列化。

添加方法:在eclipse中,鼠标悬浮到类名上,就可以看到“添加已生成的串行版本标识”,点击即可添加serialVersionUID。

3、性能问题

序列化对象写入文件的性能会比自己手动写入文件低。

参考文献

转载地址:http://twdul.baihongyu.com/

你可能感兴趣的文章
sui picker,datetimepicker,citypicker代码整理
查看>>
Redis基础教程第2节 Redis和NoSql 介绍与应用场景
查看>>
CentOS6.6下设置grub密码方法
查看>>
Linux下DHCP服务器配置
查看>>
创建数据库恢复
查看>>
一步一步教你使用AgileEAS.NET基础类库进行应用开发-基础篇-使用UDA操纵SQL语句...
查看>>
VS2010与IIS Express
查看>>
jdis操作redis cluster
查看>>
算法学习之路|最小生成树——prime算法
查看>>
如何授予邮箱的代理发送权限
查看>>
Java Hex 16进制的 byte String 转换类
查看>>
lzg_ad:如何在VMWare中调试你的XPE
查看>>
读Linux那些事儿之我是U盘笔记(一)
查看>>
C# 标准代码排版样例
查看>>
C# asp.net常见编译|运行错误
查看>>
Ajax登录页面
查看>>
Linux查看系统block size的多种方法
查看>>
用SNMP实现对大型网络的轻松管理!
查看>>
Docker 组件如何协作?- 每天5分钟玩转容器技术(8)
查看>>
员工的不幸?还是公司的悲哀?
查看>>