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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值