首页 > 学院 > 开发设计 > 正文

Java从零开始学三十九(对象序列化)

2019-11-14 23:08:07
字体:
来源:转载
供稿:网友
java从零开始学三十九(对象序列化)一、序列化

将对象的状态存储到特定存储介质中的过程

对象序列化,就是把一个对象变为二进制的数据流的一种方法,通过对象序列化可以方便的实现对象的传输或存储。序列化保存对象的“全景图”,构建对象的“全景天窗”.如果一个类的对象想被序列化,则对象所在的类必须实现java.io.Serializable接口二、对象的序列化和反序列化要想完成对象的输入或输出,还必须依靠对象输出流(ObjectOutputStream)和对象输入流(ObjectInputStream)使用对象输出流输出序列化对象的步骤,有时也称为序列化,而使用对象输入流读入对象的过程,有时也称为反序列化序列化步骤:
  1. 创建一个对象输出流ObjectOutputStream
  2. writeObject()方法输出序列化对象

反序列化步骤:

  1. 创建一个对象输入流ObjectInputStream
  2. readObject()方法读取流中的对象
三、对象输出流(ObjectOutputStream)和对象输入流(ObjectInputStream)3.1、对象输出流:ObjectOutputStream
No.方法或常量类型描述
1public ObjectOutputStream(OutputStream out) throws IOException构造传入输出的对象
2public final void writeObject(Object obj) throws IOException普通输出对象
此类的使用形式与PRintStream非常的相似,在实例化时也需要传入一个OutputStream的子类对象,之后根据传入的OutputStream子类的对象不同,输出的位置也不同。3.2、对象输入流:ObjectInputStream
No.方法或常量类型描述
1public ObjectInputStream(InputStream in) throws IOException构造构造输入对象
2public final Object readObject() throws IOException, ClassNotFoundException普通从指定位置读取对象
此类也是InputStream的子类,与PrintStream类的使用类似,此类同样需要接收InputStream类的实例才可以实例化四、transient关键字当使用Serializable接口实现序列化操作时,如果一个对象中的某个属性不希望被序列化的话,则可以使用transient关键字进行声明
import java.io.Serializable;public class Person implements Serializable {     // 此类的对象可以被序列化    private transient String name;            // 此属性将不被序列化    private int age;                // 此属性将被序列化    public Person(String name, int age) {        this.name = name;        this.age = age;    }    public String toString() {            // 覆盖toString(),输出信息        return "姓名:" + this.name + ";年龄:" + this.age;    }}
五、实现反序列化注意事项
  • 反序列化过程无需要使用构造器生成对象
  • 按顺序反序列化恢复对象
  • 父类Serializable或者存在无参数构造方法
六、例子
package com.pb.serializable;import java.io.Serializable;/* * 学生类 并实现接口Serializable接口,使用之可以序列化 *//* * 序列化 * 1.创建一个对象,这个对象将被序列化,并写入文件中,前提是这个类实现了Serializable接口 * 2.实例化ObjectOutputStream的对象 * 3.调用ObjectOutputStream的writerObject()方法,将对象写入流中 * 4.关闭流 * transient关键字 * 可以保护对象中的敏感信息不被写入到文件中 * 反序列化 * 1.实例化ObjectInputStream对象 * 2.调用ObjectInputStream的readObject()方法,获取对象时,要进行强制类型转换 * 3.关闭流 */public class Student implements Serializable {    private String name; // 姓名    private int age; // 年龄    private String gender; // 性别    private transient String passWord; // 密码属性不能被序列化    // 构造方法    public Student() {        // 无参    }    // 有参数    public Student(String name, int age, String gender, String password) {        this.name = name;        this.age = age;        this.gender = gender;        this.password = password;    }    //getter、setter方法    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        if(age>0&&age<150)        this.age = age;    }    public String getGender() {        return gender;    }    public void setGender(String gender) {        if(gender.equals("男") || gender.equals("女"))        this.gender = gender;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }    // 自我介绍    public void say() {        System.out.println("姓名:" + this.name + "/t年龄:" + this.age + "/t性别:"                + this.gender+"/t密码 : "+this.password);    }}

序列化:

package com.pb.serializable;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import java.util.ArrayList;import java.util.List;/* * 序列化 * 1.创建一个对象,这个对象将被序列化,并写入文件中,前提是这个类实现了Serializable接口 * 2.实例化ObjectOutputStream的对象 * 3.调用ObjectOutputStream的writerObject()方法,将对象写入流中 * 4.关闭流 * transient关键字 * 可以保护对象中的敏感信息不被写入到文件中 */public class SerializableObj {    public static void main(String[] args) {            try {                //1.声明一个文件输出流                FileOutputStream    fos = new FileOutputStream("d:/test/obj.txt");                //2.声明ObjectOutputStream流对象                ObjectOutputStream oos=new ObjectOutputStream(fos);                //也可以2步合一步                //ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("d:/test/obj.txt"));                Student stu1=new Student("张三", 23, "男", "123456");                Student stu2=new Student("李四", 24, "女", "123123");                Student stu3=new Student("王五", 25, "男", "123321");                Student stu4=new Student("赵六", 26, "男", "999999");                //创建集合并添加                List<Student> list=new ArrayList<Student>();                list.add(stu1);                list.add(stu2);                list.add(stu3);                list.add(stu4);                //3.将student对象序列化,写入输出oos流                oos.writeObject(stu1);                oos.writeObject(stu2);                oos.writeObject(stu3);                oos.writeObject(stu4);                oos.writeObject(list);                //4.关闭流                oos.close();                fos.close();                System.out.println("=======序列化完成======");            } catch (FileNotFoundException e) {                e.printStackTrace();            } catch (IOException e) {                e.printStackTrace();            }                        }}

反序列化:

package com.pb.serializable;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.util.List;/* * 反序列化 * 1.实例化ObjectInputStream对象 * 2.调用ObjectInputStream的readObject()方法,获取对象时,要进行强制类型转换 * 3.关闭流 */public class ReadSerializableObj {    public static void main(String[] args) {                try {            //1.声明一个文件输出流            FileInputStream    fis = new FileInputStream("d:/test/obj.txt");            //2.实例化ObjectInputStream            ObjectInputStream ois=new ObjectInputStream(fis);            //也可以全2为一            //ObjectInputStream ois=new ObjectInputStream(new FileInputStream("d:/test/obj.txt"));            //3.声明一个Student对象和集合            System.out.println("=====反序列化学生对象=======");            Student stu1=    (Student) ois.readObject();            stu1.say();            Student stu2=    (Student) ois.readObject();            stu2.say();            Student stu3=    (Student) ois.readObject();            stu3.say();            Student stu4=    (Student) ois.readObject();            stu4.say();            System.out.println("=====反序列化集合对象=======");            List<Student> list=(List<Student>) ois.readObject();            for (Student s : list) {                s.say();            }                        //4.关闭流            ois.close();            fis.close();            System.out.println("====反序列完成====");        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }}

结果:

=====反序列化学生对象=======姓名:张三    年龄:23    性别:男    密码 : null姓名:李四    年龄:24    性别:女    密码 : null姓名:王五    年龄:25    性别:男    密码 : null姓名:赵六    年龄:26    性别:男    密码 : null=====反序列化集合对象=======姓名:张三    年龄:23    性别:男    密码 : null姓名:李四    年龄:24    性别:女    密码 : null姓名:王五    年龄:25    性别:男    密码 : null姓名:赵六    年龄:26    性别:男    密码 : null====反序列完成====

从结果中可以看到:password使用transient关键字后,没有被序列化,反序列化中,读出的是默认字段类型的默认值null

七、包含引用类型属性的对象序列化

引用类必须也为可序列化

public class Teacher implements Serializable {    private String name; // 姓名    private int age; // 年龄    private String gender; // 性别    private transient String password; // 密码属性不能被序列化        private Student stu;          //这里的Student类必须也是可以序列化的,}

这里有个Teacher类,但属性中有一个Student类的对象,这时Teacher要实现序列时,Student必须也要实现Serializable接口才可以

7.1、序列化算法
  • 对象分配序列号
  • 当程序试图序列化一个对象时,将会检查是否已经被序列化,只有序列化后的对象才能被转换成字节序列输出
  • 如果对象已经被序列化,则程序直接输出一个序列化编号,而不在重新序列化
7.2、序列化机制

Teacher类:

package com.pb.serializable;import java.io.Serializable;/* * 教师类实例Serializable接口 */public class Teacher implements Serializable {    private String name; // 姓名    private int age; // 年龄    private String gender; // 性别    private transient String password; // 密码属性不能被序列化        private Student stu;          //这里的Student类必须也是可以序列化的,    //构造方法    public Teacher() {        //无参数    }    public Teacher(String name, int age, String gender, String password,            Student stu) {        //有参数        this.name = name;        this.age = age;        this.gender = gender;        this.password = password;        this.stu = stu;    }    //getter、setter方法    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String getGender() {        return gender;    }    public void setGender(String gender) {        this.gender = gender;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }    public Student getStu() {        return stu;    }    public void setStu(Student stu) {        this.stu = stu;    }    // 自我介绍        public void say() {            System.out.println("姓名:" + this.name + "/t年龄:" + this.age + "/t性别:"                    + this.gender+"/t密码 : "+this.password);        }            }

序列化和化序列化类:

package com.pb.serializable;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;/* * 老师类的序列化和反序列化 2个老师引用同一个学生对象 */public class WriterTeacherObj {    public static void main(String[] args) {                /*         * 序列化         * 1.序列化时时候,会查找当前对象的序列化编号是否存在,不存在,保存该对象         * 2.写入操作时,当对象的序列化编号存在时候,会输出一个当前对象的序列化编号,而不是当前对象         * 3.反序列化对象时, 程序会自动查找,当前对象的序列化编号,之后如果,发现当前的对象的序列化编号被其它对象引用时,则返回同一个对象         */        try {            //1.实例化ObjectOutputStream            ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("d:/test/teacher.txt"));            //2.实例化老师对象            Student student=new Student("马达", 23, "男", "123123");            //2个老师引用同一个学生对象            Teacher teacher_han=new Teacher("韩冰", 22, "女", "123456789", student);            Teacher teacher_zhang=new Teacher("张三丰", 108, "男", "123456789", student);            //3.对象序列            oos.writeObject(teacher_han);            oos.writeObject(teacher_zhang);            //4.关闭流            oos.close();            System.out.println("====================序列化完成=================");        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        /*         * 反序列化         */        System.out.println("==================开始反序列化================");        try {            //1.实例化ObjectInputStream对象            ObjectInputStream ois=new ObjectInputStream(new FileInputStream("d:/test/teacher.txt"));            //2.反序列声明一个Teacher对象强制类型转换            Teacher teacher_han=(Teacher) ois.readObject();            Teacher teacher_zhang=(Teacher) ois.readObject();            //3.输入Teacher中的信息            System.out.println("==================老师信息================");            teacher_han.say();            teacher_zhang.say();            System.out.println("=================老师中学生信息=============");            teacher_han.getStu().say();            teacher_zhang.getStu().say();            //4.关闭流            ois.close();            System.out.println("===========反序列化完成=========");                                    //判断2个老师的学生是否为同一个            if(teacher_han.getStu()==teacher_zhang.getStu()){                System.out.println("张老师和韩老师教的是同一个学生");            }else{                System.out.println("张老师和韩老师教的不是同一个学生");            }        } catch (IOException e) {            e.printStackTrace();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }}

结果:

====================序列化完成===================================开始反序列化==================================老师信息================姓名:韩冰    年龄:22    性别:女    密码 : null姓名:张三丰    年龄:108    性别:男    密码 : null=================老师中学生信息=============姓名:马达    年龄:23    性别:男    密码 : null姓名:马达    年龄:23    性别:男    密码 : null===========反序列化完成=========张老师和韩老师教的是同一个学生


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表