Java 对象序列化

要使一个对象可以序列化,必须实现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)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值