Java 使用 Kryo 序列化
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原生序列化相容,但不支持跨平台。因此,在實際開發中,應根據具體需求選擇合適的序列化方式。