java serializable protobuf kyro 序列化

Java 使用 Kryo 序列化

陳瑞泰 John Chen 2023/04/10 16:20:27
947

Java 使用 Kryo 序列化

 

  Java序列化是指將Java Object轉換為byte[],以便在網路上傳輸或者在HD上存儲。 Java提供了多種序列化方式,下面是比較常用的幾種:

 

*Java原生序列化(Java Serialization)


Java原生序列化是Java標準庫提供的序列化方式,通過實現java.io.Serializable接口,可以將Java對象序列化為byte[],也可以將byte[]反序列化為Java Object。 Java原生序列化簡單易用,但存在以下缺點:

1. 序列化的 byte[] 較大,佔用空間較多。
2. 反序列化時會進行完整性校驗,導致性能較差。
3. 序列化後的 byte[] 是機器相關的,不具有跨平台特性。

 

*JSON序列化

 

JSON是一種輕量級的數據交換格式,常用於前後端通信、數據存儲等場景。 Java中常用的JSON序列化工具包括Jackson、Gson、FastJson等。 JSON序列化優點如下(與 Java Serialization 比較):

1. byte[]較小,佔用空間較少。
2. 跨語言、跨平台,具有良好的兼容性。
3. 序列化和反序列化速度快。

 

 

Protobuf序列化

 

Protobuf是Google開源的一種輕量級的數據交換格式,與JSON類似,但更加高效,序列化後的數據大小較小。 Java中常用的Protobuf序列化工具包括Google的protobuf-java。 Protobuf序列化優點如下:

1. byte[] 非常小,佔用空間極少。

2. 序列化和反序列化速度非常快。
3. 跨語言、跨平台,具有良好的兼容性。

但是它在開發實作有一個缺點,由於必需先生成 protobuf-java 檔案,而不同的平台語言需要使用不同的檔案,這會比較麻煩,故若不是有跨平台需求個人首選不會是它。

 

Kryo 序列化

 

Kryo 庫也是一個常用的 Java 序列化工具。 Kryo 庫比 Java 原生序列化更快、序列化後的byte[]更小,但不太支持跨語言序列化。 Kryo 庫也可以通過實現 Java 序列化接口來進行序列化和反序列化,但相比於 Java 原生序列化,Kryo 庫的序列化和反序列化速度更快,並且序列化後的byte[]也更小。它的優點如下:
1. 序列化和反序列化速度非常快,比 Java 原生序列化快得多。
2. 序列化後的byte[]非常小,佔用空間極少。

 

以下是一個簡單的 Java 使用 Kryo 序列化的範例:

首先,你需要先安裝 Kryo Lib,可以透過 Maven 等方式引入。接著,你只需要定義一個類別,讓 Kryo 序列化對象。

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import java.io.*;

public class KryoSerializationExample {
    static class Person  {
        private String name;
        private int age;

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

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }
    }

    public static void main(String[] args) throws IOException {
        Kryo kryo = new Kryo();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Output output = new Output(baos);

        Person person = new Person("John", 30);
        kryo.writeObject(output, person);

        output.close();

        byte[] bytes = baos.toByteArray();

        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        Input input = new Input(bais);

        Person deserializedPerson = kryo.readObject(input, Person.class);
        input.close();

        System.out.println("Name: " + deserializedPerson.getName());
        System.out.println("Age: " + deserializedPerson.getAge());
    }
}
 

在這個範例中,定義了一個 Person 類別。下一步使用 Kryo 進行序列化和反序列化。在 main 方法中,我們首先創建一個 Kryo 實例。創建一個 ByteArrayOutputStream 以及一個 Output 對象,並使用 kryo.writeObject() 方法將 Person 對象序列化到 Output 中。接著,我們將 ByteArrayOutputStream 中的內容轉換成一個 byte[]。然後,我們創建一個 ByteArrayInputStream 和一個 Input 對象,並使用 kryo.readObject() 方法將 byte[] 反序列化成一個新的 Person 對象。最後,我們使用反序列化後的 Person 對象中的方法來獲取屬性值,並在控制台中印出來。



當使用 Kryo 序列化物件時,你也可以使用 writeClassAndObject() 和 readClassAndObject() 方法來序列化和反序列化任意類型的物件,而不需要顯式地指定類型,這與上個範例有著很大的差別。以下是一個使用 writeClassAndObject() 和 readClassAndObject() 的範例:

import com.esotericsoftware.kryo.Kryo;

import com.esotericsoftware.kryo.io.Input;

import com.esotericsoftware.kryo.io.Output;

import java.io.*;


public class KryoSerializationExample {

    public static void main(String[] args) throws IOException {

        Kryo kryo = new Kryo();


        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        Output output = new Output(baos);


        String message = "Hello, World!";

        kryo.writeClassAndObject(output, message);


        output.close();


        byte[] bytes = baos.toByteArray();


        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);

        Input input = new Input(bais);


        String deserializedMessage = (String) kryo.readClassAndObject(input);

        input.close();


        System.out.println("Deserialized message: " + deserializedMessage);

    }

}
 

在這個範例中,我們創建了一個 Kryo 實例。接著創建了一個 ByteArrayOutputStream 和一個 Output 對象,並使用 writeClassAndObject() 方法將一個字串 "Hello, World!" 序列化到 Output 中。由於我們並沒有顯式指定物件的類型(上個範例中會指定 Xxxx.class),Kryo 會自動將其類型信息一起序列化。

 

然後將 ByteArrayOutputStream 中的內容轉換成一個 byte[]。接著創建了一個 ByteArrayInputStream 和一個 Input 對象,並使用 readClassAndObject() 方法將 byte[] 反序列化成一個新的物件,並自動恢復其類型信息。

 

最後反序列化後的物件強制轉換為字串類型,並在控制台中印出來。注意,在這個範例中,並沒有顯式地指定物件的類型(Xxxxx.class),而是讓 Kryo 自動序列化和反序列化類型。

 

  總的來說,Java原生序列化簡單易用,但存在性能問題和跨平台問題;JSON序列化具有良好的兼容性和速度,但數據大小較大;Protobuf序列化則是在數據大小和速度上都有很好的表現,但開發較麻煩;Kryo序列化速度與Protobuf不相上下,簡單易用與Java原生序列化相容,但不支持跨平台。因此,在實際開發中,應根據具體需求選擇合適的序列化方式。

陳瑞泰 John Chen