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

相关推荐
一条咸鱼_SaltyFish4 分钟前
远程鉴权中心设计:HTTP 与 gRPC 的技术决策与实践
开发语言·网络·网络协议·程序人生·http·开源软件·个人开发
我即将远走丶或许也能高飞15 分钟前
vuex 和 pinia 的学习使用
开发语言·前端·javascript
沐知全栈开发22 分钟前
SQL LEN() 函数详解
开发语言
剑锋所指,所向披靡!35 分钟前
C++之类模版
java·jvm·c++
钟离墨笺36 分钟前
Go语言--2go基础-->基本数据类型
开发语言·前端·后端·golang
Coder_Boy_1 小时前
基于SpringAI的在线考试系统-0到1全流程研发:DDD、TDD与CICD协同实践
java·人工智能·spring boot·架构·ddd·tdd
sheji34161 小时前
【开题答辩全过程】以 面向高校校园的物物交换系统设计与实现为例,包含答辩的问题和答案
java·eclipse
小郭团队1 小时前
1_7_五段式SVPWM (传统算法反正切+DPWM3)算法理论与 MATLAB 实现详解
开发语言·嵌入式硬件·算法·matlab·dsp开发
卓怡学长1 小时前
m115乐购游戏商城系统
java·前端·数据库·spring boot·spring·游戏
2501_944526421 小时前
Flutter for OpenHarmony 万能游戏库App实战 - 蜘蛛纸牌游戏实现
android·java·python·flutter·游戏