Java 序列化 和 反序列化
序列化和反序列化
序列化是将对象的状态信息转化为可以存储或者传输的形式的过程(即将对象写入IO流中)
- 一般将一个对象存储到一个存储媒介,例如档案或记忆体缓冲
- 在网络传输过程中,可以是字节或、XML、JSON等格式
反序列化是将字节、XML、JSON等格式还可以还原成原来的对象(即从IO流中恢复对象)
序列化的好处
-
,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里)
-
利用序列化实现远程通信,即
Java对象的序列化和反序列化
在JAVA中,对象的序列化和反序列化被广泛的应用到 远程方法调用 及 网络传输 中
Java 序列化常用接口 - Serializable
public interface Serializable {
}
- 如果要序列化的类有父类,要想将在父类中定义过的变量序列化下来,那么父类也应该实现
java.io.Serializable
接口- 若一个类的成员变量不是基本数据类型,也不是String类型的时候,而是其他引用类型时,则该成员必须是可序列化的,否则会导致该类无法完成序列化
public class User implements Serializable {
private String name;
private String age;
public User() {
System.out.println("无参构造方法");
}
public User(String name, String age) {
this.name = name;
this.age = age;
System.out.println("有参构造方法");
}
//set、get省略
@Override
public String toString() {
return "User{'name' :" + name + ",'age' :" + age + "}";
}
}
public class TestSerializable {
public static void main(String[] args) {
try {
//序列化对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
User user = new User("wen", "12");
oos.writeObject(user);//文件存储对象的序列化编码
//反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
User user1 = (User) ois.readObject();
System.out.println(user1.toString());//User{'name' :wen,'age' :12}
} catch (Exception e) {
e.printStackTrace();
}
}
}
可变的对象中的内容发生改变时,此时进行序列化,却
public class TestSerializable {
public static void main(String[] args) {
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
User user1 = new User("wen", "20");
System.out.println("修改前:" + user1.toString());//修改前:User{'name' :wen,'age' :20}
oos.writeObject(user1);
User1.setName("cheng");
System.out.println("修改后:" + User1.toString()); //修改后:User{'name' :cheng,'age' :20}
oos.writeObject(User1);
User u1 = (User) ois.readObject();
User u2 = (User) ois.readObject();
System.out.println(u1 == u2);//true
System.out.println(u1.getName().equals(u2.getName()));//true
System.out.println(u1.getName());//wen
} catch (Exception e) {
e.printStackTrace();
}
}
}
当反序列化时,被 transient 修饰的属性则赋予默认值。
序列化和反序列化注意点
- 所有需要网络传输的对象都需要实现序列化接口,通过建议所有的 javaBean 都实现 Serializable 接口 ,如果想让某个变量不被序列化,使用 transient 修饰
- 序列化对象的引用类型成员变量,也必须是可序列化的,否则,会报错
- 反序列化时必须有序列化对象的class文件
- 当通过文件、网络来读取序列化后的对象时,必须按照实际写入的顺序读取
- 单例类序列化,需要重写 readResolve() 方法;否则会破坏单例原则
- 同一对象序列化多次,只有第一次序列化为二进制流,以后都只是保存序列化编号,不会重复序列化
- 建议所有可序列化的类加上 serialVersionUID 版本号,方便项目升级
- 数组不能显式地声明 serialVersionUID,因为它们始终都有默认的计算值,但是对于数组类,无需匹配 serialVersionUID
- 可以通过序列化和反序列化的方式实现对象的深拷贝