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

相关推荐
我登哥MVP5 小时前
Spring Boo从“会用”到“精通”:Spring Boot 入门
java·spring boot·后端·spring·maven·intellij-idea·mybatis
skywalk81635 小时前
Tree-sitter是一个解析器生成器工具和一个增量解析库。它可以为源文件构建具体的语法树,并在编辑源文件时有效地更新语法树
开发语言·编程
染翰5 小时前
Java 实现 Git 自动克隆工具,打包成 Windows 独立 EXE(免安装JDK)
java·git·后端
AI视觉网奇5 小时前
Bambu Studio 发现 xx个开放边
开发语言·人工智能·python
七老板的blog5 小时前
多阶段 AI 评测流水线架构设计与实践
java·人工智能·spring
qq_458148205 小时前
科大讯飞实时语音识别(rtasr)真实项目踩坑经验总结与手把手教学真实可运行Demo
java·开发语言·websocket·语音识别
三品吉他手会点灯5 小时前
C语言学习笔记 - 46.运算符和表达式 - 运算符4 - 对初学运算符的一些建议
c语言·开发语言·笔记·学习
创业之路&下一个五年5 小时前
mvvm中v和vm关系,vm中v和m的关系?
java·开发语言·javascript
阿昌喜欢吃黄桃5 小时前
Java优质开源AI项目
java·ai·langchain·开源·rag·springai·langchain4j
SilentSamsara5 小时前
缓存策略实战:Redis + Python 多级缓存设计与失效策略
开发语言·redis·python·缓存·性能优化