本文共 5986 字,大约阅读时间需要 19 分钟。
要使一个对象可以序列化,必须实现Serializable或者Externalizable标记接口
使用对象流(ObjectInputStream/ObjectOutputStream)可以读写序列化对象
一.序列化对象
普通java对象的序列化
先定义一个普通的可序列化对象
public class Person implements Serializable{
private int age; private String name; private int weight; private int height; private int[] intArray=new int[]{1,2,3,4,5}; private String[] strArray=new String[]{"a","b","c"}; static ArrayList<String> list=new ArrayList<String>(); static { list.add("beijing"); list.add("wuhan"); }//省略get和set方法
}
序列化实现
/**
* 将对象序列化后保存到文件 */ public static void object2File(){ Person p=new Person(); p.setAge(10); p.setHeight(120); p.setName("zhang"); p.setWeight(90); try { ObjectOutputStream objOut=new ObjectOutputStream(new FileOutputStream("person.txt")); objOut.writeObject(p); objOut.close(); System.out.println("对象已保存"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 从文件中加载序列化对象 */ public static void file2Object(){ Person p=null; try { ObjectInputStream objIn=new ObjectInputStream(new FileInputStream("person.txt")); p=(Person)objIn.readObject(); System.out.println("从文件中读取对象Person:"); System.out.println(p.getAge()+" "+p.getHeight()+" "+p.getName()+" "+p.getWeight()); //验证数组和基本数据集合的序列化问题,结果:可行 System.out.println(Arrays.toString(p.getIntArray())); System.out.println(Arrays.toString(p.getStrArray())); System.out.println(Arrays.toString(p.getList().toArray())); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
问题:对象引用的序列化,有对象A,B,C,A和B都含有C的引用,我们依次序列化A,B,C.会产生多少个对象?
实例验证:
Test_A 引用Test_C
public class Test_C implements java.io.Serializable{
}class Test_A implements java.io.Serializable{
Test_C c; public Test_A(Test_C c){ this.c=c; } public Test_C getC() { return c; } public void setC(Test_C c) { this.c = c; } }查看比较:
/**
* 含引用对象的序列化问题 */ public static void test2(){ Test_C c=new Test_C(); Test_A a=new Test_A(c); Test_A b=new Test_A(c); //写入 try { ObjectOutputStream objOut=new ObjectOutputStream(new FileOutputStream("Test_C.txt")); objOut.writeObject(c); objOut.writeObject(a); objOut.writeObject(b); objOut.close(); System.out.println("对象已保存"); } catch (Exception e) { e.printStackTrace(); } Test_C c1=null; Test_A a1=null; Test_A b1=null; //读取 try { ObjectInputStream objIn=new ObjectInputStream(new FileInputStream("Test_C.txt")); c1=(Test_C)objIn.readObject(); a1=(Test_A)objIn.readObject(); b1=(Test_A)objIn.readObject(); //读取的对象是新建的 System.out.println(c==c1); System.out.println(a==a1); System.out.println(b==b1); /*对象的引用是不变的,也就是说只有一个对象Test_C * */ System.out.println(c1==a1.getC()); System.out.println(c1==b1.getC()); System.out.println(a1.getC()==b1.getC()); } catch (Exception e) { e.printStackTrace(); } }说明,Java的序列化机制:
虚拟机对每一个对象维护一个序列化编号,当首次序列化对象时会创建一个序列化编号,当多次序列化同一个对象时,只是引用一个序列化编号.注意当原来对象的值改变后,再次序列化的值也不会改变.
二.自定义序列化
/**
* 自定义序列化, * 通过覆盖下列方法实现自定义序列化 * * 1.private void writeObject(java.io.ObjectOutputStream out) throws IOException; * 2.private void readObject(java.io.ObjectInputStream in) throws IOException,ClassNotFoundException ; * 3.private void readObjectNoData() throws ObjectStreamException; * 4.private Object writeReplace() throws ObjectStreamException ; * * 1,2要同时使用才能正确解析.3,4是可选的; * 通过验证得知: * 对象在序列化时会首先调用对象本身的方法writeReplace(),该方法可以将对象替换成另一个对象B,然后再序列化B. * 之后再调用 writeObject()方法(如果B中有的话). * 读取序列化对象的时候会先调用对象本身的readObject()方法. * 注意:writeObject()与readObject()具体步骤应该是相对应的,否则无法正确读取对象;*/ public class CustomSerializable {
public static void main(String[] args) {
object2File(new Color(),"color.txt"); }public static void object2File(Object obj, String filename) {
try {
ObjectOutputStream objOut = new ObjectOutputStream( new FileOutputStream(filename)); objOut.writeObject(obj); objOut.close(); System.out.println("对象已保存"); ObjectInputStream objIn=new ObjectInputStream(new FileInputStream("color.txt")); Color c=(Color)objIn.readObject(); System.out.println(c.getValue()); // int n=(Integer)objIn.readObject(); // System.out.println(n); } catch (Exception e) { e.printStackTrace(); } } }class Color implements java.io.Serializable {
private int value=10; public int getValue() { return value; }public void setValue(int value) {
this.value = value; }private void writeObject(java.io.ObjectOutputStream out) throws IOException {
System.out.println("1调用方法writeObject()"); out.writeInt(22); }private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException { System.out.println("1调用方法readObject()"); value=in.readInt(); } private void readObjectNoData() throws ObjectStreamException { System.out.println("1调用方法readObjectNoData()"); }private Object writeReplace() throws ObjectStreamException {
System.out.println("1调用方法writeReplace()"); return new Color(); // return new Integer(2); } }
第二种自定义序列化(完全定制)
/**
* 自定义序列化的另一种方式是实现java.io.Externalizable * 注意,必须显式提供无参的构造方法. */ public class CustomSerializable2 { public static void main(String[] args) { Rect r=new Rect(); try { ObjectOutputStream objOut = new ObjectOutputStream( new FileOutputStream("rect.txt")); objOut.writeObject(r); objOut.close(); System.out.println("对象已保存"); ObjectInputStream objIn=new ObjectInputStream(new FileInputStream("rect.txt")); Rect r2=(Rect)objIn.readObject(); System.out.println(r2.getA()+" "+r2.getB()); objIn.close(); } catch (Exception e) { e.printStackTrace(); }}
}
class Rect implements java.io.Externalizable{ private int a=1; private int b=2; public Rect(){} public int getA() { return a; } public void setA(int a) { this.a = a; } public int getB() { return b; } public void setB(int b) { this.b = b; } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.a=in.readInt(); this.b=in.readInt(); } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeInt(a); out.writeInt(b); } }
三.序列化版本问题
java在反序列化对象时会检查序列化版本,类的修改会导致反序列化失败,为了避免这种情况通常在类中设置序列化ID
private static fianl long serialVersionID=(value)
转载地址:http://xvvqj.baihongyu.com/