Java基础——序列化与反序列化

基本定义

何谓序列化?序列化就是将一个对象的状态信息转换为可以存储可传输形式的过程。在持久存储区和临时存储区将状态信息保存,并在必要时期将其复原为一个Java对象,这就是它的存在意义。

使用环境

1.把对象存储为持久化的字节序列;

2.在网络上传输对象信息时需要把对象转为二进制流传输,只有序列化后才能这么做;

序列化方法

实现serializable接口后,这个Class便有了被序列化的能力。拥有ObjectInputStream和ObjectOutputStream方法,OOS的writeObject(obj)方法将对象写入数据流中,OIS的readObject()从流中读取数据转换为对象。

序列化ID的作用

主要是作为版本号实现版本对照作用。只有ID【版本号】一致的客户端和服务器端才能进行正常的序列化与反序列化。除此之外还取决于两端的功能代码和类路径。

序列化的主要运用场景

1.对敏感字段的加密

public class Demo implements Serializable {
	private static final long serialVersionUID = -5849475956593027241L;
	
	private String password;
	
	public Demo setPassword(String pass) {
		password = pass;
		return this;
	}
	public String getPassword() {
		return password;
	}
	
	private void writeObject(ObjectOutputStream out) {
		PutField put;
		try {
			put = out.putFields();
			password = password + "secret";
			put.put("password", password);
			System.out.println("加密后的密码" + password);
			out.writeFields();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void readObject(ObjectInputStream in) {
		try {
			GetField get = in.readFields();
			Object obj = get.get("password", "");
			String tmpPass = obj.toString();
			System.out.println("这是要解密的字段:" + tmpPass);
			int index = tmpPass.indexOf("secret");
			password = tmpPass.substring(0, index);
			System.out.println("这是解密后的字段:" + password);
		} catch (ClassNotFoundException | IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		try {
			ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("result.obj"));
			out.writeObject(new Demo().setPassword("mmmMMM"));
			out.close();
			
			ObjectInputStream in = new ObjectInputStream(new FileInputStream("result.obj"));
			Demo newDemo = (Demo) in.readObject();
			System.out.println(newDemo.getPassword());
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
	}
}

需要注意的是本处的两个private方法,当在main主函数中存在readObject(ObjectOutputStream xx)和writeObject(ObjectInputStream xx)时由JVM优先调用此read和write方法若不存在则调用java.io.ObjectOutputStream和java.io.ObjectInputStream中的默认readObject和writeObject方法。输出如下:

加密后的密码mmmMMMsecret
这是要解密的字段:mmmMMMsecret
这是解密后的字段:mmmMMM
mmmMMM

此加密方式是在写入文件过程中进行加密,产生的文件,result.obj,用UE打开是这样的:

aced 0005 7372 0024 636f 6d2e 6d65 632e
6162 6f75 745f 7365 7269 616c 697a 6162
6c65 2e64 656d 6f2e 4465 6d6f aed2 7c9b
fd15 9757 0300 014c 0008 7061 7373 776f
7264 7400 124c 6a61 7661 2f6c 616e 672f
5374 7269 6e67 3b78 7074 000c 6d6d 6d4d
4d4d 7365 6372 6574 78

而其中ae d2 7c 9b fd 15 97 57正是序列化ID-5849475956593027241的16进制化,6d6d 6d4d 4d4d则是密码mmmMMM的16进制表示,可见,writeObject的方式进行数据流交互的安全性并不是很高,且当所需传输数据仅为密码时,这样的数据流较为笨重。

2.保证相同序列号的两端记性数据交互

据说,实现序列化的类,即实现了serializable接口的类如果不进行UID的设置就会由于UID不同而产生异常。这是我的实验:

public class UserModel implements Serializable{
	/*
	 * 咩有设置UID
	 */
	private String name;
	private String password;
//	private String sex;
	
	public UserModel() {
	}
	
	public String getName() {
		return name;
	}
	public UserModel setName(String name) {
		this.name = name;
		
		return this;
	}
	public String getPassword() {
		return password;
	}
	public UserModel setPassword(String password) {
		this.password = password;
		
		return this;
	}
	
	public String toString() {
		return name + " " + password;
	}
}

主函数如下:

public class Demo {
	private void secretlize(UserModel user) {
		try {
			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("result.obj"));
			oos.writeObject(user);
			System.out.println("序列化完成!");
			oos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private Object deSecretlize() {
		Object result = null;
		try {
			ObjectInputStream ois = new ObjectInputStream(new FileInputStream("result.obj"));
			result = ois.readObject();
			System.out.println("反序列化成功!");
			ois.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		return result;
	}
	
	public static void main(String[] args) {
		UserModel user = new UserModel().setName("zhangsan").setPassword("1234");
		Demo demo = new Demo();
		demo.secretlize(user);
		UserModel newUser = (UserModel) demo.deSecretlize();
		System.out.println(newUser);
	}
}

输出如下:可见十分正常。但为了避免不必要的错误还是设置为好。

序列化完成!
反序列化成功!
zhangsan 1234

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值