# 08.序列化和Json解析

453 阅读4分钟

08.序列化和Json解析

1.序列化的概念

序列化:(Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程,具体到过程是将数据结构或者对象转化为二进制或字符串的过程.

反序列化: 将序列化之后的二进制转换为数据结构或者是对象的过程.

持久化:将对象或者数据结构序列化后的二进制以文件形式存储起来.

序列化方案:

  • Serializable/Externalizable

  • Parcelable

  • json,xml,probuf...等等,属于广义的序列化

2.Serializable/Externalizable

2.1 Serializable 的序列化

在使用序列化时候,保证对象都有无参的构造函数,因为序列化会反射产生一个新的对象. 主要是使用ObjectOutputStream的方法,来进行序列化操作.

  • public final void writeObject(Object obj) throws IOException 用来将对象写入指定的输出流 将文件写入到指定的输出流. 使用transient关键字 忽略一些关键字的序列化. 也可以实现两个方法实现精细化管理序列化字段,系统在序列化时候会反射调用这两个方法.private void writeObject(ObjectOutputStream out) throws IOExceptionprivate void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException

  • 使用SerialVersionUID 来进行版本管理,反序列化时候检测到版本不一致会报错.

2.2 Externalizable 序列化

Externalizable 接口要求类需要显示的实现对象的序列化过程,即实现接口要求得两个序列化方法.

  • public void writeExternal(ObjectOutput out) throws IOException 序列化过程方法,要求序列化过程要和反序列化的顺序是一致的.
  • public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException 反序列化过程方法,要求过程要和序列化的顺序是一致的.

举例如下: 几个序列化的类

public class User implements Serializable {
    private String name;
    private int age;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = 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;
    }

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

}

public class Dog implements Externalizable {
    private String name;
    private int age;

    public Dog() {
    }

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

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

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

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


public class Person implements Serializable {
    transient private int age;

    public int getAge() {
        return age;
    }

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

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();//本方法是实现默认序列化的方法
        out.writeInt(age);
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();  //本方法是实现默认反序列化的方法
        age = in.readInt();
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

}

序列化操作:


public class SerializableUtils {

    public static void serializableObj(@NotNull Object obj, @NotNull String path) throws Exception {
        final File file = new File(path);
        if (!file.exists()) {
            file.createNewFile();
        }
        try (ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(path));) {
            outputStream.writeObject(obj);
        }

    }

    public static <T> T unSerializableObj(String path) throws Exception {
        try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(path));) {
            final Object o = objectInputStream.readObject();
            objectInputStream.close();
            return (T) o;
        }
    }

    public static void exInSerialTest(Object o, String path) {
        File file = new File(path);
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
             ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
             FileOutputStream outputStream = new FileOutputStream(file);) {
            byte[] buf = null;
            objectOutputStream.writeObject(o);
            buf = byteArrayOutputStream.toByteArray();
            outputStream.write(buf);
            outputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Object exInSerialTest(String path) {
        File file = new File(path);
        byte[] buf = new byte[(int) file.length()];
        try (FileInputStream inputStream = new FileInputStream(file);) {
            final int read = inputStream.read(buf);
            try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buf);
                 ObjectInputStream objectOutputStream = new ObjectInputStream(byteArrayInputStream);) {
                final Object o = objectOutputStream.readObject();
                return o;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}


    public static byte[] objectToBytes(Object object) {
        if (Objects.isNull(object)) {
            return null;
        }
        if (!(object instanceof Serializable)) {
            return null;
        }
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
            objectOutputStream.writeObject(object);
            objectOutputStream.flush();
            return outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public Object arrayToObject(byte[] array) {

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(array);
        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
            final Object o = objectInputStream.readObject();
            return o;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

执行测试方法:


public class Main {
    public static void main(String[] args) {
        personOut();
    }

    public void ObjToFile() {
        User user = new User("zhangsan", 14);
        try {
            SerializableUtils.serializableObj(user, "zhangsan.out");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void personIn() {
        Person person = new Person();
        person.setAge(10);
        try {
            SerializableUtils.serializableObj(person, "person.out");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void personOut() {
        try {
            final Object o = SerializableUtils.unSerializableObj("person.out");
            System.out.println((Person) o);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void fileToObj() {
        Object o = null;
        try {
            o = SerializableUtils.unSerializableObj("zhangsan.out");
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (o instanceof User) {
            System.out.println(o);
        }
    }

    public static void writeDogExternal() {
        Dog dog = new Dog();
        dog.setAge(12);
        dog.setName("ddd");
        SerializableUtils.exInSerialTest(dog, "dog.out");
    }

    public static void readDogExternal() {
        final Object o = SerializableUtils.exInSerialTest("dog.out");
        System.out.println(o);
    }
}

序列化是直接从二进制文件中生成的对象,不会调用对象的构造方法。序列化类似于一个深拷贝,对象的地址完全不同,对象的内容属性才是相同的。序列化是为了进程之间进行交换数据为目的,持久化是为了把文件保存到本地,持久化可以基于序列化。