Java 序列化与反序列化

一、什么是序列化?为何要序列化?java

    Java 序列化就是指将对象转换为字节序列的过程,而反序列化则是只将字节序列转换成目标对象的过程。面试

    咱们都知道,在进行浏览器访问的时候,咱们看到的文本、图片、音频、视频等都是经过二进制序列进行传输的,那么若是咱们须要将Java对象进行传输的时候,是否是也应该先将对象进行序列化?答案是确定的,咱们须要先将Java对象进行序列化,而后经过网络,IO进行传输,当到达目的地以后,再进行反序列化获取到咱们想要的对象,最后完成通讯。浏览器

 

二、如何实现序列化网络

  2.一、使用到JDK中关键类 ObjectOutputStream 和ObjectInputStreamide

    ObjectOutputStream 类中:经过使用writeObject(Object object) 方法,将对象以二进制格式进行写入。工具

    ObjectInputStream 类中:经过使用readObject()方法,从输入流中读取二进制流,转换成对象。this

 

  2.二、目标对象须要先实现 Seriable接口
spa

  

咱们建立一个Student类:code

public class Student implements Serializable {
    private static final long serialVersionUID = 3404072173323892464L;
    private String name;
    private transient String id;
    private String age;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id='" + id + '\'' +
                ", age='" + age + '\'' +
                '}';
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public Student(String name, String id) {
        System.out.println("args Constructor");
        this.name = name;
        this.id = id;
    }

    public Student() {
        System.out.println("none-arg Constructor");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

}

 

        

      代码中Student类实现了Serializable 接口,而且生成了一个版本号:视频

private static final long serialVersionUID = 3404072173323892464L;

      首先:

      一、Serializable 接口的做用只是用来标识咱们这个类是须要进行序列化,而且Serializable 接口中并无提供任何方法。

      二、serialVersionUid 序列化版本号的做用是用来区分咱们所编写的类的版本,用于判断反序列化时类的版本是否一直,若是不一致会出现版本不一致异常。

      三、transient 关键字,主要用来忽略咱们不但愿进行序列化的变量

 

    2.三、将对象进行序列或和反序列化

      2.3.1 第一种写入方式:

public static  void main(String[] args){
        File file = new File("D:/test.txt");
        Student student = new Student("孙悟空","12");
        try {
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(file));
            outputStream.writeObject(student);
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
            Student s = (Student) objectInputStream.readObject();
            System.out.println(s.toString());
            System.out.println(s.equals(student));
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

      建立对象Student ,而后经过ObjectOutputStream类中的writeObject()方法,将对象输出到文件中。

      而后经过ObjectinputStream 类中的readObject()方法反序列化,获取对象。

 

       2.3.2 第二种写入方式:

在Student 类中实现writeObject()和readObject()方法:

  private void writeObject(ObjectOutputStream objectOutputStream) throws IOException {
        objectOutputStream.defaultWriteObject();
        objectOutputStream.writeUTF(id);

    }

    private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
        objectInputStream.defaultReadObject();
        id = objectInputStream.readUTF();
    }

      经过这中方式进行序列话,咱们能够自定义想要进行序列化的变量,将输入流和输出流传入对线实例中,而后进行序列化以及反序列化。

  

      2.3.3 第三种写入方式:

Student 实现 Externalnalizable接口 而不实现Serializable 接口

 Externaliable 接口是 Serializable 的子类,有着和Serializable接口一样的功能:

public class Student implements Externalizable {
    private static final long serialVersionUID = 3404072173323892464L;
    private String name;
    private transient String id;
    private String age;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id='" + id + '\'' +
                ", age='" + age + '\'' +
                '}';
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public Student(String name, String id) {
        System.out.println("args Constructor");
        this.name = name;
        this.id = id;
    }

    public Student() {
        System.out.println("none-arg Constructor");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }


    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(name);
        out.writeObject(id);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        name = (String) in.readObject();
        id = (String) in .readObject();
    }

}

 

   经过和前面的第二种写入方法对比,咱们能够发现他们的实现原理都是十分的相似,不过实现Externalnalizable接口 并不支持第一种序列化方法,它只可以经过实现接口中的writeExternal()和readExternal()方法实现对象的序列化。

 

 

三、面试中关于序列化的问题:

    一、什么是序列化,如何实现序列化

        java中对象的序列化就是将对象转换成二进制序列,反序列化则是将二进制序列转换成对象

        Java 实现序列化有多种方式

          一、首先须要使用到工具类ObjectInputStream 和ObjectOutputStream 两个IO类

          二、实现Serializable 接口:

              有两种具体序列化方法:

                  2.1 直接经过ObjectOutputStream 和 ObjectInputStream 类中的 writeObject()和readObject()方法

                  2.2 经过在序列化对象中实现writeObject()和readObject()方法,传入ObjectOutputStream和ObjectInputStream对象,完成序列化

          三、实现Externalizable 接口:

                  只可以经过实现接口中的writeExternal()和readExternal()方法实现对象的序列化


     二、transient 关键字?如何将transient修饰符修饰的变量序列化?
        
transient 的做用是用来屏蔽咱们不但愿进行序列化的变量,是对象在进行序列化和反序列话的过程当中忽略该变量。
        咱们能够经过上述序列化方法中的 实现writeObject 和readObject 方法,在方法中调用输出流或输入流的writeUTF()和readUTF()方法。
        或者经过实现Externalizable 接口,实现writeExternal()和readExternal()方法,而后再自定义序列话对象。

     
      三、如何保证序列化和反序列化后的对象一致?(若有异议望指正)
       
 对于这个问题我在查阅了一些资料以后,发现并不能保证序列化和反序列化以后的对象是一致的,由于咱们在反序列化的过程当中,是先建立一个对象,        而后再经过对对象进行赋值来完成对象的反序列化,这样问题就来了,在建立了一个新的对象以后,对象引用和本来的对象并非指向同一个目标。        所以咱们只能保证他们的数据和版本一致,并不能保证对象一致。
相关文章
相关标签/搜索