序列化和反序列化(二)——Serializable 接口
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,则类出现警告,但这是次要的,更重要的是序列化时将根据Java(TM)对象序列化规范为该类计算一个默认的serialVersionUID值,这就要求反序列化时使用的类与序列化时使用的类必须完全相同(有相同的属性和方法),否则反序列化失败,因为反序列化时serialVersionUID的值也是根据Java(TM)对象序列化规范计算出来的默认值,由于序列化类代码和反序列化类代码不同,则serialVersionUID的值肯定不同;但在实际开发中序列化类代码和反序列化类代码极有可能不同,在这种情况下为了反序列化成功就要求显式声明serialVersionUID常量且值要相同。serialVersionUID的生成策略有两种:一个是固定的 1L,一个是根据Java(TM)对象序列化规范生成的 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();
}
}
}
上一篇: 序列化和反序列化(三)——父类的序列化
下一篇: Ubuntu下安装chrome浏览器