欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

序列化和反序列化(二)——Serializable 接口

程序员文章站 2022-06-16 16:54:36
...

Serializable 接口:该接口没有方法或字段,仅用于标识由该接口实现类创建的对象是可序列化的。

       示例:

import java.io.Serializable;

public class UserInfo implements Serializable {

	private static final long serialVersionUID = -564040236692883153L;
	private int age;
	private String name;

	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "name='" + name + '\'' + ", age=" + age;
	}
}
import java.io.*;

public class Test {
	
	/**
	 * 序列化
	 * 
	 * @author GaoHuanjie
	 */
	public static void serialize(){
		UserInfo userInfo = new UserInfo();
		userInfo.setAge(23);
		userInfo.setName("Tom");
		System.out.println(userInfo);
		ObjectOutput objectOutput = null;
		try {
			objectOutput = new ObjectOutputStream(new FileOutputStream("D:\\user_info.ser"));
			objectOutput.writeObject(userInfo);
			objectOutput.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (objectOutput!=null) {
				try {
					objectOutput.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 反序列化
	 * 
	 * @author GaoHuanjie
	 */
	public static void deserialize(){
		ObjectInput objectInput = null;
		try {
			objectInput = new ObjectInputStream(new FileInputStream("D:\\user_info.ser"));
			UserInfo userInfo = (UserInfo) objectInput.readObject();
			System.out.println(userInfo);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (objectInput!=null) {
				try {
					objectInput.close();
				} catch (IOException e) {
					e.printStackTrace();
				} 
			}
		}
	}

	public static void main(String[] args) {
		serialize();//序列化
		deserialize();//反序列化
	}
}

serialVersionUID常量

       实现Serializable接口的类须显式声明serialVersionUID常量,该常量作用如下:反序列化能否成功取决于三方面,首先序列化和反序列化类所在包相同,其次序列化和反序列化类的类名相同,最后序列化和反序列化类serialVersionUID的值要相同,两个类中的代码可以不同,如果不指定serialVersionUID,则类出现警告,但这是次要的,更重要的是序列化时将根据JavaTM)对象序列化规范为该类计算一个默认的serialVersionUID值,这就要求反序列化时使用的类与序列化时使用的类必须完全相同(有相同的属性和方法),否则反序列化失败,因为反序列化时serialVersionUID的值也是根据JavaTM)对象序列化规范计算出来的默认值,由于序列化类代码和反序列化类代码不同,则serialVersionUID的值肯定不同;但在实际开发中序列化类代码和反序列化类代码极有可能不同,在这种情况下为了反序列化成功就要求显式声明serialVersionUID常量且值要相同。serialVersionUID的生成策略有两种:一个是固定的 1L,一个是根据JavaTM)对象序列化规范生成的 long 类型数据;如果没有特殊需求,推荐使用固定值,这样便于序列化类代码和反序列化类serialVersionUID一致;如果限制某些用户的使用,则推荐第二种生成策略。

transient 关键字

       在序列化时,transient 关键字修饰的成员变量不会被序列化;在反序列化时,transient 关键字修饰的成员变量被赋以默认值,如整型为0,浮点型为0.0,引用类型为null

static关键字

       在序列化时,static关键字修饰的成员变量不会被序列化。序列化保存的是对象的状态,静态变量属于类的状态,因此序列化并不保存静态变量,即序列化信息中不包含这个静态成员域。

import java.io.Serializable;

public class UserInfo implements Serializable {

	private static final long serialVersionUID = 1L;
	private static int count;
	public UserInfo() {
		count++;
	}
	public String toString() {
		return "count:" + count;
	}
}

       static修饰的成员变量,序列化和反序列化代码在一个进程中执行时会序列化成功,因为序列化时jvm已经把静态变量加载进来了,所以反序列化时获取的是加载好的静态变量,如下例子:

import java.io.*;

public class Test {

	public static void main(String[] args) {
		try {
			ObjectOutput objectOutput = new ObjectOutputStream(new FileOutputStream("user_info.ser"));
			objectOutput.writeObject(new UserInfo());
			objectOutput.close();

			ObjectInput objectInput = new ObjectInputStream(new FileInputStream("user_info.ser"));
			UserInfo userInfo = (UserInfo) objectInput.readObject();
			System.out.println(userInfo);
			objectInput.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

       static修饰的成员变量,序列化和反序列化代码不再一个进程,由于反序列化时是重新加载静态变量,所以静态变量是初始值,如下列子:

序列化:

import java.io.*;

public class Test1 {

	public static void main(String[] args) {
		try {
			ObjectOutput objectOutput = new ObjectOutputStream(new FileOutputStream("user_info.ser"));
			objectOutput.writeObject(new UserInfo());
			objectOutput.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

反序列化:
import java.io.*;

public class Test2 {

	public static void main(String[] args) {
		try {
			ObjectInput objectInput = new ObjectInputStream(new FileInputStream("user_info.ser"));
			UserInfo userInfo = (UserInfo) objectInput.readObject();
			System.out.println(userInfo);
			objectInput.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}