Java之序列化

概念

  • 序列化是将对象转换为字节序列的过程(其中可以是二进制、特定的字符串、xml、json)。
  • 反序列化是将字节序列恢复为对象的过程。

序列化使用场景

  • 需要把内存中的对象保存到文件中或者数据库中(持久化)时候。
  • 跨平台通过网络传输对象时候(WebService SOAP)。
  • 通过RNI传输对象的时候 (仅限于java环境)。

实现序列化

实现序列化比较简单将需要序列化的类实现Serializable即可。但是查看源码知道,Serializable这个接口中没有方法,所以我们即可理解为一个标记,标记该类是可以被序列化的。

序列化实例

//对象类
import java.io.Serializable;

public class Student implements Serializable {

	private static final long serialVersionUID = -1556557458139596779L;
	private String name;
	private int age;
	
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = 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;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
}


//序列化方法
public static void serialize(Object obj,String outFile){
	try {
		ObjectOutputStream oos = 
			new ObjectOutputStream(new FileOutputStream(outFile));
		//往磁盘中写入当前内存中对象的状态 
		oos.writeObject(obj);
		oos.flush();
		oos.close();
	} catch (IOException e) {
		e.printStackTrace();
	}

}


//反序列方法
public static Object deSerialize(String readFile){
	try {
		ObjectInputStream ois = 
			new ObjectInputStream(new FileInputStream(readFile));
		Object obj =ois.readObject();
		ois.close();
		return obj;
	} catch (IOException | ClassNotFoundException e) {
		e.printStackTrace();
	}
	return null;
}

//调用
Student s = new Student("KKY",22);
String sFileName = "student.out";
serialize(s,sFileName);

Student sde=(Student) deSerialize("student.out");
System.out.println(sde);

默认序列化机制

如果仅仅只是让某个类实现Serializable接口,而没有其它任何处理的话,则就是使用默认序列化机制。但是默认序列化机制效率非常低,所以一般是不使用java默认序列化规则。

序列化ID

private static final long serialVersionUID = -1556557458139596779L;

序列化ID主要针对跨服务器、跨平台情况,如果序列化ID不一致就会无法反序列化,所以一般我们都需要去生成序列化ID。

其他注意点

指定不序列化

在属性上添加transient关键字,即可指明该属性不被序列化,同时静态变量不能被序列化。但是如果想序列化transient修饰的变量,就需要自定义序列化规则。虽然Serializable没有定义方法,但是有三个方法可以自己实现来修改默认序列化规则:

private void writeObject(java.io.ObjectOutputStream out)
    throws IOException
private void readObject(java.io.ObjectInputStream in)
    throws IOException, ClassNotFoundException;
private void readObjectNoData()
    throws ObjectStreamException;

所以即可修改如下:

transient private int age;


//JDK自动调用 扩展序列化规则一个方法
private void writeObject(ObjectOutputStream out) throws IOException{
	out.defaultWriteObject();
	out.writeInt(age);
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
	in.defaultReadObject();
	age = in.readInt();
}

上述也是可以序列化age属性,不过这两个方法应该用于扩展序列化规则。

readResolve()方法

当我们使用单例模式时,本来是期望只生成一个对象实例,不过如果该类是可序列化的,那么情况就不一样了此时,我们可以增加对readResolve方法的实现,来确保在同一个JVM中只有一个单例对象的使用。

private Student() { 
	super();
}  
 
private static final Student INSTANCE = new Student();  

public static Student getInstance() {
  	return INSTANCE;
}  

private Object readResolve()
 throws ObjectStreamException {  
  return INSTANCE;   
 }  

Externalizable接口

如果想自定义序列化内容可以实现Externalizable接口。实现Externalizable接口需要自己定义序列化和反序列化方法。

mport java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

//JDK将不会调用默认的序列化规则
//完全使用自定义序列化规则
public class Person implements Externalizable {

	private String name;
	private int age;
	
	
	public Person() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = 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;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	//扩展序列化的方法
	@Override
	public void readExternal(ObjectInput in)
	 throws IOException, ClassNotFoundException {
		name = (String) in.readObject();
		age = in.readInt();
	}
	@Override
	public void writeExternal(ObjectOutput out)
	 throws IOException {
		out.writeObject(name);
		out.writeInt(age);
		
	}
}

序列化前和序列化后的对象的关系

深复制。

网络环境中的序列化

java环境RMI Remote Method Invoker 远程方法调用
	仅限于java平台中调用
	序列化的效率非常低
	
	
WebService SOAP Simple Object Access Protrol 简单对象传出协议
	跨语言、跨平台
	还是没有解决效率低的问题
	可读性非常差,基于xml传输的
	
JSON
	跨语言、跨平台
	可读性非常强
	序列化效率有所提高,但目前来说还不是最高的

序列化发展方向

主要发展方向其实就是往更高性能和更小的传输大小。

参考引用

https://blog.csdn.net/lingzhm/article/details/45047765

相关推荐
程序员_三木3 分钟前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
是小崔啊13 分钟前
开源轮子 - EasyExcel01(核心api)
java·开发语言·开源·excel·阿里巴巴
tianmu_sama19 分钟前
[Effective C++]条款38-39 复合和private继承
开发语言·c++
黄公子学安全22 分钟前
Java的基础概念(一)
java·开发语言·python
liwulin050623 分钟前
【JAVA】Tesseract-OCR截图屏幕指定区域识别0.4.2
java·开发语言·ocr
jackiendsc28 分钟前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
Yuan_o_28 分钟前
Linux 基本使用和程序部署
java·linux·运维·服务器·数据库·后端
Oneforlove_twoforjob32 分钟前
【Java基础面试题027】Java的StringBuilder是怎么实现的?
java·开发语言
羚羊角uou34 分钟前
【C++】优先级队列以及仿函数
开发语言·c++
FeboReigns40 分钟前
C++简明教程(文章要求学过一点C语言)(1)
c语言·开发语言·c++