Serialization
Serialization
该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象。
整个过程都是
public final void writeObject(Object x) throws IOException
上面的方法序列化一个对象,并将它发送到输出流。相似的
public final Object readObject() throws IOException,
ClassNotFoundException
该方法从流中取出下一个对象,并将对象反序列化。它的返回值为
序列化机制
序列化主要有三个用途
- 对象持久化
(persistence) :对象持久化是指延长对象的存在时间。通常状况下,当程序结束时,程序中的对象不再存在。对象持久化是指延长对象的存在时间。通常状况下,当程序结束时,程序中的对象不再存在。如果通过序列化功能,将对象保存到文件中,就可以延长对象的存在时间,在下次程序运行是再恢复该对象。 - 对象复制:通过序列化,将对象保存在内存中,可以再通过此数据得到多个对象的副本。
- 对象传输:通过序列化,将对象转化字节流后,可以通过网络发送给另外的
Java 程序。
默认的序列化机制写到流中的数据有
- 对象所属的类
- 类的签名
- 所有的非
transient 和非static 的属性 - 对其他对象的引用也会造成对这些对象的序列化
- 如果多个引用指向一个对象,那么会使用
sharing reference 机制
序列化是将对象的状态信息转换为可存储或传输的形式的过程。我们都知道,
序列化使用
为了演示序列化在
public class Employee implements java.io.Serializable
{
public String name;
public String address;
public transient int SSN;
public int number;
public void mailCheck()
{
System.out.println("Mailing a check to " + name
+ " " + address);
}
}
请注意,一个类的对象要想序列化成功,必须满足两个条件:
-
该类必须实现
java.io.Serializable 接口。 -
该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的。
如果你想知道一个
序列化对象
public class SerializeDemo
{
public static void main(String [] args)
{
Employee e = new Employee();
e.name = "Reyan Ali";
e.address = "Phokka Kuan, Ambehta Peer";
e.SSN = 11122333;
e.number = 101;
try
{
FileOutputStream fileOut =
new FileOutputStream("/tmp/employee.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(e);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in /tmp/employee.ser");
}catch(IOException i)
{
i.printStackTrace();
}
}
}
为什么一个类实现了
private void writeObject0(Object obj, boolean unshared) throws IOException {
...
if (obj instanceof String) {
writeString((String) obj, unshared);
} else if (cl.isArray()) {
writeArray(obj, desc, unshared);
} else if (obj instanceof Enum) {
writeEnum((Enum) obj, desc, unshared);
} else if (obj instanceof Serializable) {
writeOrdinaryObject(obj, desc, unshared);
} else {
if (extendedDebugInfo) {
throw new NotSerializableException(cl.getName() + "\n"
+ debugInfoStack.toString());
} else {
throw new NotSerializableException(cl.getName());
}
}
...
}
从上述代码可知,如果被写对象的类型是
反序列化对象
下面的
public class DeserializeDemo
{
public static void main(String [] args)
{
Employee e = null;
try
{
FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
e = (Employee) in.readObject();
in.close();
fileIn.close();
}catch(IOException i)
{
i.printStackTrace();
return;
}catch(ClassNotFoundException c)
{
System.out.println("Employee class not found");
c.printStackTrace();
return;
}
System.out.println("Deserialized Employee...");
System.out.println("Name: " + e.name);
System.out.println("Address: " + e.address);
System.out.println("SSN: " + e.SSN);
System.out.println("Number: " + e.number);
}
}
注意,
serialVersionUID
虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化
这是因为,在进行反序列化时,