java 序列化

Java序列化详解
本文详细介绍了Java中的序列化机制,包括Serializable接口的实现方法、Externalizable接口的应用以及自定义序列化过程。通过具体示例展示了如何序列化和反序列化Java对象,并探讨了序列化过程中的一些关键概念如版本兼容性和transient关键字。

1.序列化  Serializable    

MySerialize.java

package my.java.serialize;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
/*
 * 对象序列化  允许把内存中的java对象转换成平台无关的二进制流,从而允许将这种二进制流持久的保存在磁盘,或者通过网络传输
 * 反序列化      将上述的二进制流恢复成原来的java对象
 * 
 * ObjectOutputStream    将序列化对象写入文件
 * ObjectInputStream     反序列化
 * 
 * 两种方式           实现Serializable 接口
 *          实现Externalizable 接口
 */
public class MySerialize  {
	
	public static void main(String[] args) throws Exception {
		//myserialize1();
		//序列化机制          同一个对象  只在最开始的时候  序列化一次
		//1.所有保存到磁盘中的对象都有一个序列化编号
		//2.当程序视图序列化一个对象时,首先检查该对象是否被序列化过,只有该对象从未(在本次虚拟机中)被序列化过,系统才会将该对象转换成字节序列并输出
		//3.如果某个对象已经被序列化,程序将只是直接输出一个序列化编号,而不是再次重新序列化该对象
		myserialize2();
	}

	private static void myserialize1() throws Exception {
		//使用该方式  将对象以二进制流输出到文件       即 字节流  以文本方式打开文件是乱码
		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("D:\\object.txt"));
		
		User user1 = new User("张三", new Date(), 20);
		User user2 = new User("张四", new Date(), 21);
		User user3 = new User("张五", new Date(), 22);
		
		//该方式输入文件的是字节流
		outputStream.writeObject(user1);
		outputStream.writeObject(user2);
		outputStream.writeObject(user3);
		outputStream.close();
		
		// 解析字节流 
		ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("D:\\object.txt"));
		User user11 = (User) inputStream.readObject();
		User user22 = (User) inputStream.readObject();
		User user33 = (User) inputStream.readObject();
		inputStream.close();
		
		System.out.println(user11.toString());
		System.out.println(user22.toString());
		System.out.println(user33.toString());
	}
	private static void myserialize2() throws Exception {
		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("D:\\object2.txt"));
		
		User user = new User("张三", new Date(), 20);
		System.out.println(user.toString());
		outputStream.writeObject(user);
		user.setName("张四");
		user.setBirthday(new Date());
		user.setAge(21);
		System.out.println(user.toString());
		outputStream.writeObject(user);
		outputStream.close();
		
		System.out.println("-----------分界线--------------");

		// 解析字节流 
		ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("D:\\object2.txt"));
		User user11 = (User) inputStream.readObject();
		User user22 = (User) inputStream.readObject();
		inputStream.close();
		
		System.out.println(user11.toString());
		System.out.println(user22.toString());
		/* 输出结果
		User [name=张三, birthday=Fri Jun 02 11:16:29 CST 2017, age=20]
		User [name=张四, birthday=Fri Jun 02 11:16:29 CST 2017, age=20]
		-----------分界线--------------
		User [name=张三, birthday=Fri Jun 02 11:16:29 CST 2017, age=20]
		User [name=张三, birthday=Fri Jun 02 11:16:29 CST 2017, age=20]*/
	}
	
}

User.java

package my.java.serialize;

import java.io.Externalizable;
import java.io.Serializable;
import java.util.Date;

/*
 * 对象序列化  允许把内存中的java对象转换成平台无关的二进制流,从而允许将这种二进制流持久的保存在磁盘,或者通过网络传输
 * 反序列化      将上述的二进制流恢复成原来的java对象
 * 
 * 两种方式           实现Serializable 接口
 *          实现Externalizable 接口
 */

public class User implements Serializable {
	
	/**
	 *  版本值     为了在反序列化时确保序列化版本的兼容性
	 *  标识该java类的序列化版本    如果一个类升级后,只要serialVersionUID值不变,序列化机制会把他们当成同一个序列化版本
	 *  
	 *  如果不显式指定  serialVersionUID,该值由JVM根据类的相关信息计算,而修改后的类的计算结果与修改之前的类的计算结果往往不同,
	 *  从而造成对象的反序列化因为类版本不兼容而失败
	 */
	private static final long serialVersionUID = 1L;

	private String name;
	
	private Date birthday;
	
	private int age;

	public User(String name, Date birthday, int age) {
		super();
		this.name = name;
		this.birthday = birthday;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

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

2. 序列化  Serializable

MySerialize2.java

package my.java.serialize;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
/*
 * 对象序列化  允许把内存中的java对象转换成平台无关的二进制流,从而允许将这种二进制流持久的保存在磁盘,或者通过网络传输
 * 反序列化      将上述的二进制流恢复成原来的java对象
 * 
 * ObjectOutputStream    将序列化对象写入文件
 * ObjectInputStream     反序列化
 * 
 * 两种方式           实现Serializable 接口
 *          实现Externalizable 接口
 *          
 * 自定义序列化
 * 
 * transient 关键字  只能修饰实例变量      指定java序列化时无须理会该实例变量
 * private transient Date birthday;
 */
public class MySerialize2  {
	
	public static void main(String[] args) throws Exception {
		// 测试 transient
		//myserialize();
		// 在User2中添加   writeObject     readObject 方法进行测试
		//myserialize2();
		// 在User2类中添加     writeReplace 方法  进行测试
		//myserialize3();
	}

	private static void myserialize() throws Exception {
		//使用该方式  将对象以二进制流输出到文件       即 字节流  以文本方式打开文件是乱码
		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("D:\\object.txt"));
		User2 user1 = new User2("张三", new Date(), 20);
		User2 user2 = new User2("张四", new Date(), 21);
		User2 user3 = new User2("张五", new Date(), 22);
		//该方式输入文件的是字节流
		outputStream.writeObject(user1);
		outputStream.writeObject(user2);
		outputStream.writeObject(user3);
		outputStream.close();
		
		// 解析字节流 
		ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("D:\\object.txt"));
		User2 user11 = (User2) inputStream.readObject();
		User2 user22 = (User2) inputStream.readObject();
		User2 user33 = (User2) inputStream.readObject();
		inputStream.close();
		
		System.out.println(user11.toString());
		System.out.println(user22.toString());
		System.out.println(user33.toString());
		/* 输出结果    输出时  birthday为null
		User [name=张三, birthday=null, age=20]
		User [name=张四, birthday=null, age=21]
		User [name=张五, birthday=null, age=22]*/
	}
	private static void myserialize2() throws Exception {
		//使用该方式  将对象以二进制流输出到文件       即 字节流  以文本方式打开文件是乱码
		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("D:\\object2.txt"));
		User2 user1 = new User2("张三abc", new Date(), 20);
		User2 user2 = new User2("张四abc", new Date(), 21);
		User2 user3 = new User2("张五abc", new Date(), 22);
		//该方式输入文件的是字节流
		outputStream.writeObject(user1);
		outputStream.writeObject(user2);
		outputStream.writeObject(user3);
		outputStream.close();
		
		//写入文件的类型是    my.java.serialize.User2
		
		// 解析字节流 
		ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("D:\\object2.txt"));
		User2 user11 = (User2) inputStream.readObject();
		User2 user22 = (User2) inputStream.readObject();
		User2 user33 = (User2) inputStream.readObject();
		inputStream.close();
		
		System.out.println(user11.toString());
		System.out.println(user22.toString());
		System.out.println(user33.toString());
		/* 输出结果
		User [name=cba三张, birthday=Fri Jun 02 13:14:01 CST 2017, age=20]
		User [name=cba四张, birthday=Fri Jun 02 13:14:01 CST 2017, age=21]
		User [name=cba五张, birthday=Fri Jun 02 13:14:01 CST 2017, age=22]*/
	}
	
	@SuppressWarnings("unchecked")
	private static void myserialize3() throws Exception {
		//使用该方式  将对象以二进制流输出到文件       即 字节流  以文本方式打开文件是乱码
		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("D:\\object3.txt"));
		User2 user1 = new User2("张三abc", new Date(), 20);
		User2 user2 = new User2("张四abc", new Date(), 21);
		User2 user3 = new User2("张五abc", new Date(), 22);
		//该方式输入文件的是字节流
		outputStream.writeObject(user1);
		outputStream.writeObject(user2);
		outputStream.writeObject(user3);
		outputStream.close();
		
		//如果User2类中的 writeReplace  return this;    参考myserialize2 输出
		
		//写入文件的类型是    java.util.ArrayList

		// 解析字节流 
		ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("D:\\object3.txt"));
		ArrayList<Object> list = (ArrayList<Object>) inputStream.readObject();
		inputStream.close();
		
		System.out.println(list);
		/* 输出结果
		[1, 2, 3] */
		
	}
}

User2.java

package my.java.serialize;

import java.io.Externalizable;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;

/*
 * 对象序列化  允许把内存中的java对象转换成平台无关的二进制流,从而允许将这种二进制流持久的保存在磁盘,或者通过网络传输
 * 反序列化      将上述的二进制流恢复成原来的java对象
 * 
 * 两种方式           实现Serializable 接口
 *          实现Externalizable 接口
 * 自定义序列化
 * 
 * transient 关键字  只能修饰实例变量      指定java序列化时无须理会该实例变量
 */

public class User2 implements Serializable {
	
	/**
	 *  版本值     为了在反序列化时确保序列化版本的兼容性
	 *  标识该java类的序列化版本    如果一个类升级后,只要serialVersionUID值不变,序列化机制会把他们当成同一个序列化版本
	 *  
	 *  如果不显式指定  serialVersionUID,该值由JVM根据类的相关信息计算,而修改后的类的计算结果与修改之前的类的计算结果往往不同,
	 *  从而造成对象的反序列化因为类版本不兼容而失败
	 */
	private static final long serialVersionUID = 1L;

	private String name;
	
	private transient Date birthday;
	
	private int age;
	
	private void writeObject(ObjectOutputStream out) throws Exception {
		//执行默认的序列化机制
		out.defaultWriteObject();
		//将name实例变量反转后写入二进制流
		out.writeObject(new StringBuffer(name).reverse());
		//将birthday写入二进制流
		out.writeObject(birthday);
	}
	
	//重写writeReplace方法        程序在序列化对象之前,先调用该方法
	//如果该方法返回另一个java对象     则系统转化为序列化另一个对象
	private Object writeReplace() {
		//执行writeObject序列化  正常序列化
		//return this;
		ArrayList<Object> list = new ArrayList<Object>();
		list.add(1);
		list.add(2);
		list.add(3);
		return list;
	}
	private void readObject(ObjectInputStream in) throws Exception {
		//执行默认的序列化机制
		in.defaultReadObject();
		//不更改name顺序
		this.name = in.readObject().toString();
		//读入birthday
		this.birthday = (Date) in.readObject();
	}
	
	public User2() {
		System.out.println("----不-------带参数的构造器-----------");
	}
	
	public User2(String name, Date birthday, int age) {
		super();
		System.out.println("-----------带参数的构造器-----------");
		this.name = name;
		this.birthday = birthday;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

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

3. 序列化 Externalizable

MyExternalizable.java

package my.java.serialize;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;

public class MyExternalizable {
	public static void main(String[] args) throws Exception {
		//使用该方式  将对象以二进制流输出到文件       即 字节流  以文本方式打开文件是乱码
		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("D:\\object.txt"));
		User3 user1 = new User3("张三", new Date(), 20);
		User3 user2 = new User3("张四", new Date(), 21);
		User3 user3 = new User3("张五", new Date(), 22);
		//该方式输入文件的是字节流
		outputStream.writeObject(user1);
		outputStream.writeObject(user2);
		outputStream.writeObject(user3);
		outputStream.close();
		
		// 解析字节流 
		ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("D:\\object.txt"));
		User3 user11 = (User3) inputStream.readObject();
		User3 user22 = (User3) inputStream.readObject();
		User3 user33 = (User3) inputStream.readObject();
		inputStream.close();
		
		System.out.println(user11.toString());
		System.out.println(user22.toString());
		System.out.println(user33.toString());
		/* 输出结果    输出时  birthday为null
		------不------带参数构造器------
		------不------带参数构造器------
		------不------带参数构造器------
		User3 [name=三张, birthday=null, age=20]
		User3 [name=四张, birthday=null, age=21]
		User3 [name=五张, birthday=null, age=22]*/
	}
}

User3.java

package my.java.serialize;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Date;

public class User3 implements Externalizable {
	
	/**
	 *  版本值     为了在反序列化时确保序列化版本的兼容性
	 *  标识该java类的序列化版本    如果一个类升级后,只要serialVersionUID值不变,序列化机制会把他们当成同一个序列化版本
	 *  
	 *  如果不显式指定  serialVersionUID,该值由JVM根据类的相关信息计算,而修改后的类的计算结果与修改之前的类的计算结果往往不同,
	 *  从而造成对象的反序列化因为类版本不兼容而失败
	 */
	private static final long serialVersionUID = 1L;
	
	private String name;
	
	private Date birthday;
	
	private int age;
	
	//没有序列化 birthday
	@Override
	public void writeExternal(ObjectOutput out) throws IOException {
		out.writeObject(new StringBuffer(name).reverse());
		out.writeInt(age);
	}

	@Override
	public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
		this.name = in.readObject().toString();
		this.age = in.readInt();
	}
	//当使用Externalizable 机制反序列化对象时, 程序会先使用public的无参数构造器创建实例 
	//然后才执行readExternal 方法进行序列化
	//因此实现Externalizable 必须提供无参数构造器
	public User3() {
		System.out.println("------不------带参数构造器------");
	}
	
	public User3(String name, Date birthday, int age) {
		super();
		System.out.println("------带参数构造器------");
		this.name = name;
		this.birthday = birthday;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

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

 

转载于:https://my.oschina.net/u/2490316/blog/913240

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值