什么是序列化?

我们创建的对象只有在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());
}
}

注意:

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();
}
}

同理,如果父类已经实现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 Serializable
obj.setState(100);
out.writeObject(obj); // saves object with state = 100
obj.setState(200);
out.writeObject(obj); // does not save new object state 

2、版本控制

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

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

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

3、性能问题

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

参考文献

http://www.oracle.com/technetwork/articles/java/javaserial-1536170.html

Java序列化(含transient)的更多相关文章

  1. Java序列化之transient和serialVersionUID的使用

    package FileDemo; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IO ...

  2. 原!上线遇到的问题, java序列化关键字transient 修饰的属性变成null了

    1.问题描述: 某个功能点,user对象 放入session,后再另外地方取出,结果某个字段没有了.再本地和测试环境都是ok的,但是线上环境就是不行. 后来看到这个user对象的那个属性是加了tran ...

  3. Java 序列化 transient关键字

    Java 序列化 transient关键字 @author 敏敏Alexia 转自:http://www.cnblogs.com/lanxuezaipiao/p/3369962.html 1. tra ...

  4. K:java序列化与反序列化—transient关键字的使用

      首先,应该明白的是transient是java中的一个关键字,音标为 英: [ˈtrænziənt].   在了解transient关键字之前,应该先弄明白序列化和反序列化.所谓的序列化,通俗点的 ...

  5. Java 序列化与反序列化

    1.什么是序列化?为什么要序列化? Java 序列化就是指将对象转换为字节序列的过程,而反序列化则是只将字节序列转换成目标对象的过程. 我们都知道,在进行浏览器访问的时候,我们看到的文本.图片.音频. ...

  6. Java序列化与反序列化

    Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?本文围绕这些问题进行了探讨. 1.Java序列化与反序列化 Java序列化是指把Java对象转换为字节序列 ...

  7. 关于Java中的transient关键字

    Java中的transient关键字是在序列化时候用的,如果用transient修饰变量,那么该变量不会被序列化. 下面的例子中创建了一个Student类,有三个成员变量:id,name,age.ag ...

  8. Java 序列化Serializable详解

    Java 序列化Serializable详解(附详细例子) Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连 ...

  9. 关于java序列化中的一个细节

    java序列化机制的可以参考很多资料了,最近在看的时候发现了一些问题. 1. 默认的序列化机制,很多书里讲到序列化类只序列化类名,实例变量,不会实例化类变量(static)和瞬态变量(transien ...

随机推荐

  1. html引用外部js和css

    html引用外部js和css css:<link rel="stylesheet" type="text/css" href="xx.css&q ...

  2. 第一册:lesson ninety-three。

    原文:  our new neighbor. Nigel is our new next-door neighbor. He is a pilot. He was in the R.A.F. He w ...

  3. 【转载】Sqlserver强制密码过期导致数据库登录失败

    Sqlserver在设置登录账户信息的时候,有个复选框信息会被默认勾上,即强制实施密码策略,默认勾选上的还有强制密码过期.如果勾上了这个强制密码过期后,则你的账户密码在一定时间登录后会提示Sqlser ...

  4. 【转载】使用Jquery操作Cookie对象

    Cookies是一种能够让网站服务器把少量数据储存到客户端的硬盘或内存,或是从客户端的硬盘读取数据的一种技术.jQuery是一个封装好的JavaScript库,使用jQuery可以极大地简化了Java ...

  5. 路由器动态DNS设置

    路由器中的动态DNS设置非常的简单,只需要注册动态域名服务商的账号,然后在路由器中登录该账号就可以了 一.路由器动态DNS作用 无线路由器连接宽带上网后,路由器会从宽带运营商那里获取一个IP地址,这个 ...

  6. mybatis_14二级缓存

    原理: 同一级缓存原理相似,在sqlsession3不执行增删改的情况下,sqlsession2的查询结果会直接调用sqlsession1的查询结果,具体细节如下: 使用: 开启二级缓存总开关   U ...

  7. Docker 系列一(概念原理和安装).

    一.概念原理 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间 ...

  8. xpath语法笔记

    xpath是在xml文档中查找信息的语言, 其语法整理如下: 路径表达式(选取节点) div div下的所有子节点 /div 根节点下的div //div 匹配所有的div . 当前节点 .. 父节点 ...

  9. laravel接值 get post

    laravel使用一种简单的方式来访问用户提交的信息. 你可以用统一的方式来访问用户提交的信息,而不用为用户提交信息的方式操心. 引用类:use Illuminate\Support\Facades\ ...

  10. C#时间、日期 的操作

    原文地址:http://zhidao.baidu.com/link?url=q-0No1LWfdyqQKFBg8RN5h0K-X0VygSbFI4sR8lBPwDExkIIzXQivyMKqX7V1y ...