java序列化和反序列化(一)—— 概念及Demo分析

前言

Java对象的序列化和反序列化的问题,在分布式系统中常常容易被忽视。曾经在工作中踩过坑,最近又看到不少同事在这个问题上踩坑,故想写一篇博客来示警戒,同时也望能帮助到为此问题感到困惑的诸君

1. 什么是Java对象的序列化和反序列化

  • 序列化: 将Java对象转化成字节流。 可作为对象持久化的一种实现方式,但更多体现在将对象的属性和方法转换成字节流便于远程通信传输
  • 反序列化: 将字节流转换成Java对象。

2. JDK中相关的API

  • 输出流对象:java.io.ObjectOutputStream。它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化成字节流,把得到的字节流写到一个目标输出流中(如:文件输出流等)。
  • 输入流:java.io.ObjectInputStream。它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回。

3. 关于Serializable接口

  • Java对象能被序列化的前提是实现了Serializable接口或者其子接口Externalizable
  • 序列化场景多被应用于分布式场景的RPC调用,所有传输Java对象须强制实现Serializable来保证反序列化的成功(这一点将在后续铺开叙述)

4. demo及分析

Student.java

	public class Student implements Serializable {

        private String name;

        private int age;

        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;
        }

    }

SerializableTest.java(包含两个方法:一个序列化方法,一个反序列化方法)

public class SerializableTest {

    /**
     * Student序列化
     */
    public static void serialize() {

        Student student = new Student();
        student.setAge(15);
        student.setName("张三");

        ObjectOutputStream ots = null;
        try {
            //指定java对象Person序列化后的字节流输出的目标流
            ots = new ObjectOutputStream(new FileOutputStream("D:/studentStream.txt"));
            //将Person序列化成的字节流写入到目标输出流(此处为文件输出流)中
            ots.writeObject(student);
            System.out.println("序列化成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (ots != null) {
                    ots.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Student序列化字节的反序列化操作
     */
    public static void deSerialize() {
        ObjectInputStream inputStream = null;
        try {
            //指定序列化字节流的来源
            inputStream = new ObjectInputStream(new FileInputStream("D:/studentStream.txt"));
            //将字节流反序列化成Object对象(在这里进行了强转)
            Student student = (Student) inputStream.readObject();
            System.out.println("执行反序列化过程成功:" + student.getName() + "-" + student.getAge() + "岁");
        } catch (ClassNotFoundException | IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
    
    public static void main(String[] args) throws InterruptedException {
        //1. 先执行序列化方法
        serialize();
        Thread.sleep(1000);
        //2. 后执行反序列化方法
        deSerialize();
    }

}

demo分析

SerializableTest.java的main方法中:

  • 先执行序列化方法,执行后可在指定目录:"D:/studentStream.txt"中看到被序列化后的Student字节流
    java序列化和反序列化(一)—— 概念及Demo分析_第1张图片
  • 为了让反序列化执行更加直观,第二步中直接将反序列化后的Student对象信息打印出来
    java序列化和反序列化(一)—— 概念及Demo分析_第2张图片

总结

  • Java对象是否能被序列化,其前提是实现 java.io.Serializable 接口
  • 序列化的出现:为Java对象的持久化提供了一种解决方案,同时又对远程通信过程,如:分布式系统中PRC建立的连接提供了支持

《下一篇:java序列化和反序列化(二)—— serialVersionUID》

你可能感兴趣的:(java编程)