“序列化”它有话说

1.序列化概念

把对象转换为字节序列的过程称为对象的序列化
把字节序列恢复为对象的过程称为对象的反序列化
java

2.为何须要序列化

在java中socket传输数据时,数据类型每每比较难选择。可能要考虑带宽、跨语言、版本的兼容等问题。比较常见的作法有两种:一是把对象包装成JSON字符串传输,二是采用java对象的序列化和反序列化。随着Google工具protoBuf的开源,protobuf也是个不错的选择。对JSON,Object Serialize,ProtoBuf 作个对比。算法

3.如何序列化

实现了Serializable或Externalizable接口的类的对象才能被序列化,不然抛出异常。安全

import java.io.Serializable;

public class Info implements Serializable {


	private static final long serialVersionUID = -7927179583519945413L;

	private String name=null;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Info(String name, int age) {
		this.name = name;
		this.age = age;
	}
	

}
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class UseInfo {

	public static void main(String[] args) throws Exception {
		//序列化info对象
		//1) 建立一个对象输出流,它能够包装一个其余类型的目标输出流,如文件输出流;
		Info info1 =new Info("张三",18);
		Info info2 =new Info("李四",19);
		File file =new File("info.txt");
		System.out.println("文件是否已建立:"+file.exists());
		FileOutputStream fos =new FileOutputStream(file);
		//2) 经过对象输出流的writeObject()方法写对象。
		ObjectOutputStream oos =new ObjectOutputStream(fos);
		oos.writeObject(info1);
		oos.writeObject(info2);
		oos.flush();
		oos.close();
		fos.close();
		//反序列化info对象
		//1) 建立一个对象输入流,它能够包装一个其余类型的源输入流,如文件输入流;
		ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));
		Info i1=(Info)ois.readObject();
		System.out.println(i1.getName()+" "+i1.getAge());
		Info i2=(Info)ois.readObject();
		System.out.println(i2.getName()+" "+i2.getAge());
		//2) 经过对象输入流的readObject()方法读取对象。
		ois.close();
		
	}

}

对象序列化包括以下步骤:
  1) 建立一个对象输出流,它能够包装一个其余类型的目标输出流,如文件输出流;
  2) 经过对象输出流的writeObject()方法写对象。socket

对象反序列化的步骤以下:
  1) 建立一个对象输入流,它能够包装一个其余类型的源输入流,如文件输入流;
  2) 经过对象输入流的readObject()方法读取对象。工具

4.serialVersionUID的做用*

s​e​r​i​a​l​V​e​r​s​i​o​n​U​I​D​:​ ​字​面​意​思​上​是​序​列​化​的​版​本​号​,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量this

实现Serializable接口的类若是类中没有添加serialVersionUID,那么就会出现以下的警告提示spa

采用这种方式生成的serialVersionUID是1Lcode

当咱们若是想要在序列化后改变类的属性而后反序列化,好比:在Info类里再加入一个sex属性,而后执行反序列化刚才的对象,在这个时候就会抛出异常。对象

文件流中的class和classpath中的class,也就是修改事后的class,不兼容了,处于安全机制考虑,程序抛出了错误,而且拒绝载入。那么若是咱们真的有需求要在序列化后添加一个字段或者方法呢?应该怎么办?那就是本身去指定serialVersionUID。接口

Java编译器会自动给这个class进行一个摘要算法,相似于指纹算法,只要这个文件 多一个空格,获得的UID就会大相径庭的,能够保证在这么多类中,这个编号是惟一的。因此,添加了一个字段后,因为没有显指定 serialVersionUID,编译器又为咱们生成了一个UID,固然和前面保存在文件中的那个不会同样了,因而就出现了2个序列化版本号不一致的错误。所以,只要咱们本身指定了serialVersionUID,就能够在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可使用,并且还多了方法或者属性能够用。

serialVersionUID的取值

serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。若是对类的源代码做了修改,再从新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。
类的serialVersionUID的默认值彻底依赖于Java编译器的实现,对于同一个类,用不一样的Java编译器编译,有可能会致使不一样的 serialVersionUID,也有可能相同。为了提升serialVersionUID的独立性和肯定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值

显式地定义serialVersionUID有两种用途:
  ① 在某些场合,但愿类的不一样版本对序列化兼容,所以须要确保类的不一样版本具备相同的serialVersionUID;
  ② 在某些场合,不但愿类的不一样版本对序列化兼容,所以须要确保类的不一样版本具备不一样的serialVersionUID。

5.总结

1)Java序列化就是把对象转换成字节序列,而Java反序列化就是把字节序列还原成Java对象。

2)采用Java序列化与反序列化技术,一是能够实现数据的持久化,在MVC模式中非常有用;二是能够对象数据的远程通讯。

相关文章
相关标签/搜索