为什么需要序列化?
对于一个存在Java虚拟机中的对象来说,其内部的状态只是保存在内存中。JVM退出之后,内存资源也就被释放,Java对象的内部状态也就丢失了。而在很多情况下,对象内部状态是需要被持久化的,将运行中的对象状态保存下来(最直接的方式就是保存到文件系统中),在需要的时候可以还原,即使是在Java虚拟机退出的情况下。
对象序列化机制是Java内建的一种对象持久化方式,可以很容易实现在JVM中的活动对象与字节数组(流)之间进行转换,使用得Java对象可以被存储,可以被网络传输,在网络的一端将对象序列化成字节流,经过网络传输到网络的另一端,可以从字节流重新还原为Java虚拟机中的运行状态中的对象。
对象序列化相关的类与接口
1.Java类中对象的序列化工作是通过ObjectOutputStream和ObjectInputStream来完成的。
序列化对象输出操作必须通过调用:private void writeObject(ObjectOutputStream out)方法实现。这个方法将抛出IOException异常。
反序列化对象输入的操作必须通过调用private void readObject(ObjectInputStream in)方法实现。这个方法将抛出IOException和ClassNotFoundException异常。
2. 对于任何需要被序列化的对象,都必须要实现接口Serializable,它只是一个标识接口,本身没有任何成员,只是用来标识说明当前的实现类的对象可以被序列化。
3. 如果在类中的一些属性,希望在对象序列化过程中不被序列化,使用关键字transient标注修饰就可以。当对象被序列化时,标注为transient的成员属性将会自动跳过。
对象序列化应该注意的一些问题
1.当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任何的成员方法,静态的成员变量和transient标注的成员变量。
2.如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存还原,而且会是递归的方式。
3.如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。可以将这个引用标记transient,那么对象仍然可以序列化。
下面看一个实例:
定义对象,实现Serializable接口
package com.tzy.serializable;
import java.io.Serializable;
public class Product implements Serializable {
private static final long serialVersionUID = 5260133645081293623L;
private String ID;
private String title;
private double price;
public Product(String iD, String title, double price) {
ID = iD;
this.title = title;
this.price = price;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getID() {
return ID;
}
}
序列化对象,主要使用ObjectOutputStream类
package com.tzy.serializable;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class WriteObjectDemo {
public static void main(String[] args) {
Product thinkpadPC = new Product("T110", "thinkpad", 5000);
Product idelpadPC = new Product("G110", "idelpad", 4600);
String fileName = "C:\\Procuct.dat";
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName))) {
out.writeObject(thinkpadPC);
out.writeObject(idelpadPC);
} catch (FileNotFoundException e) {
System.err.println(e);
} catch (IOException e) {
System.err.println(e);
}
System.out.println("Succss!");
}
}
反序列化对象,主要使用ObjectInputStream类
package com.tzy.serializable;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class ReadObjectDemo {
public static void main(String[] args) {
Product product1 = null;
Product product2 = null;
String fileName = "C:\\Procuct.dat";
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName))) {
product1 = (Product) in.readObject();
product2 = (Product) in.readObject();
} catch (Exception e) {
System.err.println(e);
}
System.out.println(product1.getID());
System.out.println(product1.getTitle());
System.out.println(product1.getPrice());
System.out.println(product2.getID());
System.out.println(product2.getTitle());
System.out.println(product2.getPrice());
}
}