Java序列化的实现方式有哪些?

前言

Java常用的序列化方式包括基于流序列化、Json序列化、FastJson序列化、ProtoBuf序列化....

PS:基于流序列化的对象必须实现Serializable、Externalizable,会自动序列化所有非static和transient关键字修饰的成员变量

4种序列化方式实例

公共实体类

public class Student implements Serializable {
    @Protobuf(fieldType = FieldType.STRING, required = false, order = 1)
    private String name;
    @Protobuf(fieldType = FieldType.INT32, required = false, order = 2)
    private int age;
    @Protobuf(fieldType = FieldType.STRING, required = false, order = 3)
    public static String QQ = "123456";
    @Protobuf(fieldType = FieldType.STRING, required = false, order = 4)
    public transient String address = "CHINA";   // 被transient标记的变量不会被序列化(基于流)

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "org.ccccye.study.serializable.Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", QQ=" + QQ +
                ", address='" + address + '\'' +
                '}';
    }

    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 class SerializableTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Student student = new Student("john", 18);
        System.out.println(student);

        // 1. 基于流序列化
        Long t1 = System.currentTimeMillis();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(baos);
        out.writeObject(student);
        System.out.println("serialize "+(System.currentTimeMillis()-t1)+"ms, length:"+baos.toByteArray().length);

        Long t2 = System.currentTimeMillis();
        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
        Student newStudent = (Student) in.readObject();
        System.out.println("deserialize:"+(System.currentTimeMillis()-t2)+"ms");
        System.out.println("serialize--"+newStudent);
        in.close();
        out.close();

        // 2. jackson序列化
        ObjectMapper mapper = new ObjectMapper();
        t1 = System.currentTimeMillis();
        byte[] buff = mapper.writeValueAsBytes(student);
        System.out.println("jackson serialize "+(System.currentTimeMillis()-t1)+"ms, length:"+buff.length);

        // 反序列化
        t2 = System.currentTimeMillis();
        newStudent = mapper.readValue(buff, Student.class);
        System.out.println("jackson deserialize "+(System.currentTimeMillis()-t2)+"ms");
        System.out.println("jackson--"+newStudent);

        // 3. fastjson序列化
        t1 = System.currentTimeMillis();
        buff = JSON.toJSONBytes(student);
        System.out.println("fastjson serialize "+(System.currentTimeMillis()-t1)+"ms, length:"+buff.length);

        t2 = System.currentTimeMillis();
        newStudent = (Student) JSON.parseObject(buff,Student.class);
        System.out.println("fastjson deserialize "+(System.currentTimeMillis()-t2)+"ms");
        System.out.println("fastjson=="+newStudent);

        // 4. protobuf序列化
        Codec<Student> codec = ProtobufProxy.create(Student.class, false);
        t1 = System.currentTimeMillis();
        buff = codec.encode(student);
        System.out.println("protobuf serialize "+(System.currentTimeMillis()-t1)+"ms, length:"+buff.length);

        t2 = System.currentTimeMillis();
        newStudent = codec.decode(buff);
        System.out.println("protobuf deserialize "+(System.currentTimeMillis()-t2)+"ms");
        System.out.println("protobuf--"+newStudent);
    }
}

打印结果

org.ccccye.study.serializable.Student{name='john', age=18, QQ=123456, address='CHINA'}
serialize 87ms, length:103
deserialize:166ms
serialize--org.ccccye.study.serializable.Student{name='john', age=18, QQ=123456, address='null'}
jackson serialize 231ms, length:24
jackson deserialize 91ms
jackson--org.ccccye.study.serializable.Student{name='john', age=18, QQ=123456, address='CHINA'}
fastjson serialize 226ms, length:24
fastjson deserialize 40ms
fastjson==org.ccccye.study.serializable.Student{name='john', age=18, QQ=123456, address='CHINA'}
protobuf serialize 33ms, length:23
protobuf deserialize 0ms
protobuf--org.ccccye.study.serializable.Student{name='john', age=18, QQ=123456, address='CHINA'}

性能数据经过整理后

序列化方式 序列化耗时(ms) 反序列化耗时(ms) 数据大小
Serialize 87 166 103
jackson 231 91 24
fastjson 226 40 24
protobuf 33 0 23

总结

经过测试,在数据量很少的情况下,jackson和fastjson的资源开销差不多;与json相比,原生流的反序列化和数据大小表现远远差于json,但是序列化耗时较少;最强的是protobuf在数据大小跟json一致的情况下,序列化/反序列化耗时远远低于json,甚至反序列化1个对象时耗时接近于0

参考文档

oldmee https://blog.csdn.net/javaer_lee/article/details/89098754

posted @ 2020-09-08 16:27  ccccye  阅读(446)  评论(0编辑  收藏  举报