Java序列化与反序列化


Java序列化与反序列化


Java提供了两种对象持久化的方式,分别为序列化和外部序列化

    • 序列化

      在分布式环境下,当进行远程通讯时,不管是何种类型的数据,都会以二进制序列的形式在网络上传输。序列化是一种将对象以一连串的字节描述的过程,用于解决在对对象流进行读写操做时所引起的问题。序列化能够将对象的状态写在流里进行网络传输,或者保存到文件、数据库等系统中,并在须要时把该流读取出来从新构造一个相同的对象。html

      全部实现序列化的类都必须实现Serializable接口,Serializable接口位于java.lang包中,没有任何实现方法,使用一个输出流(例如FileOutputStream)来构造一个ObjectOutputStream对象,紧接着使用该对象的writeObject(Object obj)方法就能够将obj对象写出,要恢复时可使用其对应的输入流ObjectInputStream.java

序列化有如下两个特色:数据库

    1. 若是一个类能被序列化,那么它的子类也可以被序列化。
    2. 因为static(静态)表明类的成员,transient(Java关键字,若是用transient声明一个实例变量,当对象存储时,它的值不须要维持)表明对象的临时数据,所以被声明为这两种类型的数据成员是不可以被序列化的。

      以下是序列化的代码,首先声明一个Student类继承Serializable接口,由代码中的输出(注释即为输出内容)可得静态变量SCHOOLNAME和SCHOOLID的值发生了变化,难道是静态变量也被序列化了吗?其实不是的,由于在当前的运行程序中,Student类的静态变量的值已经发生了变化,若是真的已经序列化了,那么咱们将序列化的那个函数去掉,让程序从SourceFile/Student文件中反序列化,那么获得的SCHOOLNAME应该为HeBei University,SCHOOLID的值为2,然而当咱们去掉序列化代码,直接从文件反序列化,输出SCHOOLNAME是Beijing University of Post and Telecommunications,SCHOOLID为1,说明static变量并无被序列化。编程

public class Student implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public String name;
    public int id;
    public static String SCHOOLNAME = "Beijing University of Post and Telecommunications";
    private static int SCHOOLID = 1;
    public Student(){
        name = "zhangsan";
        id = 2018111846;
    }
    public Student(String name, int id){
        this.name = name;
        this.id = id;
    }
    public static void setSchool(String school_name, int school_id){
        SCHOOLID = school_id;
        SCHOOLNAME = school_name;
    }
    public static int getSchoolID(){
        return SCHOOLID;
    }
}


public class Test {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Student student = new Student();
        student.setSchool("Hebei University",2);
        serialize(student);
        deserialize();
    }
    /**
     * 序列化student对象
     * @param student
     */
    private static void serialize(Student student){
        try {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("SourceFile/Student"));
            oos.writeObject(student);
            oos.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    /**
     * 从文件反序列化student对象
     */
    private static void deserialize(){
        try {
            FileInputStream fis = new FileInputStream("SourceFile/Student");
            Student student = (Student) new ObjectInputStream(fis).readObject();
            System.out.println(student.name);     //输出zhangsan
            System.out.println(student.id);       //输出2018111846
            System.out.println(student.SCHOOLNAME);    //输出HeBei University
            System.out.println(student.getSchoolID()); //输出2
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
    • 外部序列化

      Java语言还提供了另一种方式来实现对象持久化,即外部序列化。外部序列化与序列化的主要区别在于序列化是内置的API,只须要实现Serializable接口,开发人员不须要编写任何代码就能够实现对象的序列化,而是用外部序列化时,Externalizable接口中的方法必须有开发人员实现。所以与实现Serializable接口的方法相比,使用Externalizable编写程序的难度更大,可是因为控制权交给了开发者,在编程时有更多的灵活性,对须要持久化的那些属性能够进行控制,可能提升程序的性能。网络

以下是外部序列化的代码,当把序列化部分的代码注释到以后,发现薪金的输出仍是10000,则能够肯定当执行外部序列化时,static静态变量也被序列化了,并且方法中没有序列化id属性,则反序列化后发现id并无发生变化:分布式

public class Teacher implements Externalizable{
    private String name;
    private int id;
    private static int salary = 5000;
    public Teacher(){
        name = "zhangsan";
        id = 182566;
    }
    public static void setSalary(int s){
        salary =s;
    }
    public int getID(){
        return id;
    }
    public void setID(int id){
        this.id = id;
    }
    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        // TODO Auto-generated method stub
        Date date = (Date)in.readObject();
        name = (String)in.readObject();
        salary = (Integer)in.readObject();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        System.out.println(sdf.format(date));
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        // TODO Auto-generated method stub
        Date date = new Date();
        out.writeObject(date);
        out.writeObject(name);
        out.writeObject(salary);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        System.out.println(sdf.format(date));
    }
    public String toString(){
        return "教师名称" + name + "  薪金" + salary;
    }
}


public class Test {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.setSalary(10000);
        teacher.setID(111111);
        System.out.println(teacher.getID());        //输出111111
        serialize(teacher);
        Teacher teacher1 = deserialize();
        System.out.println(teacher1.toString());    //输出教师名称zhangsan  薪金10000
        System.out.println(teacher1.getID());       //输出182566
    }
    /**
     * 外部序列化teacher对象
     * @param teacher
     */
    private static void serialize(Teacher teacher){
        try {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("SourceFile/Teacher"));
            oos.writeObject(teacher);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    private static Teacher deserialize(){
        try {
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("SourceFile/Teacher"));
            return (Teacher)ois.readObject();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

Java反序列化

与序列化相对的是反序列化,它将流转换为对象,在序列化与反序列化的过程当中,serialVersionUID起着重要的做用,每个类都有一个特定的serialVersionUID,在反序列化的过程当中经过serialVersionUID断定类的兼容性,自定义serialVersionUID主要由以下3个优势。ide

  1. 提升程序运行效率。若是在类中未显示声明serialVersionUID,那么在序列化时会经过计算获得一个serialVersionUID。经过显示声明serialVersionUID的方式省去了计算的过程,提升了程序效率。
  2. 提升程序不一样平台上的兼容性。因为各个平台计算serialVersionUID的方式可能不一样,经过显示的方式能够彻底避免该问题。
  3. 加强程序各个版本的可兼容性。在默认状况下每一个类都有惟一的一个serialVersionUID,所以当后期对类进行修改时,类的serialVersionUID值将会发生变化,这将会致使类在修改前对象的文件在修改后没法进行反序列化操做。一样经过显示声明serialVersionUID也会解决该问题。

最后想说明,反序列化也是Java建立对象的一种方式,其余的还有new 类名()、经过clone()建立对象、经过反射机制建立对象函数

相关文章
相关标签/搜索