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

Java基础(1) 序列化与反序列化

2016-10-11 16:57 281 查看

1. 概念

Java序列化是指把Java对象转换为字节序列的过程。

Java反序列化是指把字节序列恢复为Java对象的过程。

使用场景:

内存中的对象保存到文件或数据库中

用Socket在网络上传送对象

通过RMI传输对象

2. 序列化的三种方式

仅实现Serializable接口的默认序列化

实现Serializable接口,同时定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputStream out)

实现Externalnalizable接口,同时定义readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法

3. 默认序列化

3.1. 注意事项

默认序列化是深度拷贝,不仅仅是基本对象,对所有对象都会进行复制,而不是仅仅复制对象的引用。

因为是深度拷贝,所以要求所有被序列化的对象都实现了序列化(递归检测),否则会抛出java.io.NotSerializableException异常。例外有,基本类型,基本类型的数组,枚举类型。

静态字段和transient修饰的字段默认情况下不会被序列化(自定义序列化时可以),在反序列化之后会被赋值为初始值(0,null)。

父类实现序列化,那子类也默认实现序列化。子类序列化时,默认会序列化父类内容。

父类没有实现序列化接口,子类实现了序列化接口。默认序列化时,父类成员不会进行序列化。同时,父类必须有无参数构造器。

3.2. 简单实例

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class AA implements Serializable{

/**
*
*/
private static final long serialVersionUID = 6465468687825253519L;

private int a;
public AA() {}

public AA(int a) {
this.a = a;

}

public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
@Override
public String toString() {
return "AA [a=" + a + "]";
}

}

public class SerializableTestTwo {
public static void main(String[] args) throws Exception {
//默认序列化
AA a = new AA(1);
FileOutputStream fos = new FileOutputStream( new File("/Users/irving/Documents/serializable"));
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(a);

//默认反序列化
FileInputStream fis = new FileInputStream(new File("/Users/irving/Documents/serializable"));
ObjectInputStream ois = new ObjectInputStream(fis);
AA aa = (AA) ois.readObject();
System.out.println(aa.toString());
}
}


3.3. 默认序列化的四个方法

writeReplace方法:与readResolve方法类似,可以用于控制单例对象

writeObject方法

readObject方法

readResolve方法:控制单例对象

4. 自定义序列化

不熟悉 没找到什么有用的实例

5. Externalnalizable接口序列化

当反序列化时,会先调用无参数构造器创建一个新的对象(Serializable接口后不会调用无参数构造器),然后再进行填充。所以使用这种方法时必须要有一个无参数构造器,且未public。

适合用于深度序列化,writeExternal和readExternal方法是必须的

同时实现Serializable接口与Externalnalizable接口时,Serializable接口失效。

6. serialVersionUID

默认情况下JVM会自动生成,但强烈建议一开始就定义好,且不改变。

各个JVM下相同类生成的UID不相同,且同一JVM下同一类修改后UID也会改变,所以最好一开始就指定,且不改变。

用途:

不同版本序列化兼容,则要求有相同的UID

不同版本序列化要求不兼容,则要求有不相同的UID

7. readResolve方法(effective java第77条)

对于一个正在被反序列化的对象,如果定义了readResolve方法,并且具备正确的声明,那么在反序列化之后,新建对象上的readResolve方法就会被调用,然后改方法返回对象的引用将被返回,取代新建对象。

如果依赖readResolve方法进行实例控制,带有对象引用类型的所有实例域都必须声明为transient,否则

8. 序列化存在的问题

默认序列化形式会导致在类的公共API中泄漏私有字段。

在Effective java中有很多,但没看懂

9. 资料

http://imxylz.blog.sohu.com/186773591.html

http://www.2cto.com/kf/201405/305380.html

http://www.cnblogs.com/xiohao/p/4234184.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 序列化