如何对一个java对象进行序列化?首先,对象的类需要实现Serializable接口,其次对象的域也必须都实现了Serializiable接口,最后可以使用ObjectOutputStream将对象序列化成字节流,流向网络或者文件。
以上是每个java程序员都知道的。但接下来稍微深入一些,可能会淘汰一批java程序员。首先列出关键字:transient, readObject(), writeObject(), readResolve(), serialVersionUID.
在需要序列化的对象中,存在一些域,并不需要序列化,因为对这些域序列化毫无意义,比如,对一个文件的引用,将其序列化不如将文件的路径存储下来,在对象反序列化的时候,使用文件路径重新创建文件的引用。对于此类域,可以使用关键字transient对其修饰。这样序列化程序将跳过此域。如果对象的类声明了writeObject()和readObject()方法,序列化程序将会调用对象的这两个方法。如下面的code,Employee的writeObject将File的绝对路径写入序列化流中,然后在反序列话时,读出文件绝对路径,重新对其实例化。
此外,有一些对象,比如单例,或者枚举。由于反序列化,导致单例变多例,枚举不再相等。此时,可以使用readResolve方法来解决此问题。readResolve()方法在readObject()之后,将反序列化实例返回。如下面的code,EmployeeType反序列化后,依旧保持枚举项可以用==来判断。
最后讲一下serialVersionUID。它代表两个类是相兼容的。如果一个实例序列化的时候用的是版本1.0的类,反序列化的时候,类版本已经升级为2.0,为了能使得向前兼容,可以将升级的类的serialVersionUID与之前版本的保持一致。这样,可以将版本1.0的实例反序列化成2.0版本。
执行类
public class SerializationTest { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { Employee tracy = new Employee("Tracy", EmployeeType.SECRETARY, "tracy.contract"); Manager bill = new Manager("Bill", EmployeeType.MANAGER, "bill.contract", tracy); ObjectOutputStream oos = null; ObjectInputStream ois = null; try { oos = new ObjectOutputStream(new FileOutputStream("bill.data")); oos.writeObject(bill); ois = new ObjectInputStream(new FileInputStream("bill.data")); Manager billCopy = (Manager) ois.readObject(); System.out.println(billCopy.getType() == EmployeeType.MANAGER); System.out.println(billCopy.getName()); System.out.println(billCopy.getContract().getName()); System.out.println(billCopy.getSecretary().getType() == EmployeeType.SECRETARY); System.out.println(billCopy.getSecretary().getName()); System.out.println(billCopy.getSecretary().getContract().getName()); } finally { if (oos != null) oos.close(); if (ois != null) ois.close(); } } }EmployeeType
package serialization; import java.io.File; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectStreamException; import java.io.Serializable; public class EmployeeType implements Serializable { private static final long serialVersionUID = 446408774918722110L; public static final EmployeeType EMPLOYEE = new EmployeeType("employee"); public static final EmployeeType HR = new EmployeeType("hr"); public static final EmployeeType MANAGER = new EmployeeType("manager"); public static final EmployeeType SECRETARY = new EmployeeType("secretary"); private EmployeeType(String name) { this.name = name; } public String getName() { return this.name; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); } private Object readResolve() throws ObjectStreamException { if ("employee".equals(this.name)) return EmployeeType.EMPLOYEE; if ("manager".equals(this.name)) return EmployeeType.MANAGER; if ("secretary".equals(this.name)) return EmployeeType.SECRETARY; return EmployeeType.EMPLOYEE; } private String name; }
Employee
public class Employee implements Serializable { private static final long serialVersionUID = 4227138074044013136L; private String name; private EmployeeType type; private transient File contract; public Employee(String name, EmployeeType type, String contractId) { this.setName(name); this.setType(type); String filepath = contractId+".txt"; this.setContract(new File(filepath)); } public String getName() { return name; } public void setName(String name) { this.name = name; } public EmployeeType getType() { return type; } public void setType(EmployeeType type) { this.type = type; } public File getContract() { return contract; } public void setContract(File contract) { this.contract = contract; } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeUTF(this.contract.getAbsolutePath()); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); String path = in.readUTF(); this.contract = new File(path); } }
Manager
public class Manager extends Employee{ private static final long serialVersionUID = 7105104278002669570L; private Employee secretary; public Manager(String name, EmployeeType type, String contractId, Employee secretary) { super(name, type, contractId); this.setSecretary(secretary); } public Employee getSecretary() { return secretary; } public void setSecretary(Employee secretary) { this.secretary = secretary; } }