在我們使用諸如Redis這類緩存系統時,我們往往會存在如下需求:將Java對象保存到Redis緩存中,然后在其他機器上還原回來。
Json方案
我們可以引入Json庫等方式,將Java對象序列化為Json字符串來實現這個目的,但是這樣的方案還是過于復雜。因為對于二進制類型數據,我們需要通過Base64之類的字符轉換方式將其變成Json可以存儲的字符串類型。反序列化時,又要Base64反解。這過程非常繁瑣而且嚴重影響整體的效率。
二進制方案
實際我們可以使用java.io庫中相關類,直接將Java對象轉換為二進制;還可以直接通過加載二進制數據重新構建該對象。并且這個操作支持數組、List、Set、Map等非基礎類型。
直接上代碼
核心代碼
package org.serialize.serializer;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;public class MemorySerialize {public static <T> byte[] serialize(T obj) throws Exception {ByteArrayOutputStream bos = new ByteArrayOutputStream();try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {oos.writeObject(obj);return bos.toByteArray();}}public static <T> T deserialize(byte[] data) throws Exception {ByteArrayInputStream bis = new ByteArrayInputStream(data);try( ObjectInputStream ois = new ObjectInputStream(bis)) {@SuppressWarnings("unchecked")T obj = (T) ois.readObject(); return obj;}}
}
測試代碼
數據類
下面的數據類包含了8種Java基礎類型。
為了書寫方便,我們使用了Data注解來幫我們生成諸如set/get類操作。
數據類需要繼承于java.io.Serializable接口,否則生成操作會報錯。
package org.serialize.pojo;import lombok.Data;@Data
public class BaseTypes implements java.io.Serializable{private byte byteValue;private short shortValue;private int intValue;private long longValue;private float floatValue;private double doubleValue;private char charValue;private boolean booleanValue;
}
Pom.xml
因為引入了lombok,并且需要寫單元測試,所以在pom.xml中新增如下依賴。
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>RELEASE</version><scope>provided</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>RELEASE</version><scope>test</scope></dependency>
測試代碼
基礎類型
@Testpublic void testSerializeBaseTypes() {BaseTypes baseTypes = new BaseTypes();baseTypes.setByteValue((byte) 1);baseTypes.setShortValue((short) 2);baseTypes.setIntValue(3);baseTypes.setLongValue(4L);baseTypes.setFloatValue(5.0f);baseTypes.setDoubleValue(6.0);baseTypes.setCharValue('7');baseTypes.setBooleanValue(true);try {byte[] data = MemorySerialize.serialize(baseTypes);BaseTypes baseTypesDeserialized = MemorySerialize.deserialize(data);assertEquals(baseTypes, baseTypesDeserialized);} catch (Exception e) {e.printStackTrace();fail();}}
數組
@Testpublic void testSerializeBaseTypesArray() {BaseTypes[] baseTypesArray = new BaseTypes[3];for (int i = 0; i < baseTypesArray.length; i++) {BaseTypes baseTypes = new BaseTypes();baseTypes.setByteValue((byte) (i + 1));baseTypes.setShortValue((short) (i + 2));baseTypes.setIntValue(i + 3);baseTypes.setLongValue(i + 4L);baseTypes.setFloatValue(i + 5.0f);baseTypes.setDoubleValue(i + 6.0);baseTypes.setCharValue((char) (i + 7));baseTypes.setBooleanValue(i % 2 == 0);baseTypesArray[i] = baseTypes;}try {byte[] data = MemorySerialize.serialize(baseTypesArray);BaseTypes[] baseTypesArrayDeserialized = MemorySerialize.deserialize(data);assertArrayEquals(baseTypesArray, baseTypesArrayDeserialized);} catch (Exception e) {e.printStackTrace();fail();}}
List
@Testpublic void testSerializeBaseTypesWithArrayList() {List<BaseTypes> baseTypesArrayList = new ArrayList<>();for (int i = 0; i < 3; i++) {BaseTypes baseTypes = new BaseTypes();baseTypes.setByteValue((byte) (i + 1));baseTypes.setShortValue((short) (i + 2));baseTypes.setIntValue(i + 3);baseTypes.setLongValue(i + 4L);baseTypes.setFloatValue(i + 5.0f);baseTypes.setDoubleValue(i + 6.0);baseTypes.setCharValue((char) (i + 7));baseTypes.setBooleanValue(i % 2 == 0);baseTypesArrayList.add(baseTypes);}try {byte[] data = MemorySerialize.serialize(baseTypesArrayList);List<BaseTypes> baseTypesArrayListDeserialized = MemorySerialize.deserialize(data);assertEquals(baseTypesArrayList, baseTypesArrayListDeserialized);} catch (Exception e) {e.printStackTrace();fail();}}
Set
@Testpublic void testSerializeBaseTypesWithSet() {Set<BaseTypes> baseTypesSet = new HashSet<>();for (int i = 0; i < 3; i++) {BaseTypes baseTypes = new BaseTypes();baseTypes.setByteValue((byte) (i + 1));baseTypes.setShortValue((short) (i + 2));baseTypes.setIntValue(i + 3);baseTypes.setLongValue(i + 4L);baseTypes.setFloatValue(i + 5.0f);baseTypes.setDoubleValue(i + 6.0);baseTypes.setCharValue((char) (i + 7));baseTypes.setBooleanValue(i % 2 == 0);baseTypesSet.add(baseTypes);}try {byte[] data = MemorySerialize.serialize(baseTypesSet);Set<BaseTypes> baseTypesSetDeserialized = MemorySerialize.deserialize(data);assertEquals(baseTypesSet, baseTypesSetDeserialized);} catch (Exception e) {e.printStackTrace();fail();}}
Map
@Testpublic void testSerializeBaseTypesWithMap() {Map<String, BaseTypes> baseTypesMap = new HashMap<>();for (int i = 0; i < 3; i++) {BaseTypes baseTypes = new BaseTypes();baseTypes.setByteValue((byte) (i + 1));baseTypes.setShortValue((short) (i + 2));baseTypes.setIntValue(i + 3);baseTypes.setLongValue(i + 4L);baseTypes.setFloatValue(i + 5.0f);baseTypes.setDoubleValue(i + 6.0);baseTypes.setCharValue((char) (i + 7));baseTypes.setBooleanValue(i % 2 == 0);baseTypesMap.put(String.valueOf(i), baseTypes);}try {byte[] data = MemorySerialize.serialize(baseTypesMap);Map<String, BaseTypes> baseTypesMapDeserialized = MemorySerialize.deserialize(data);assertEquals(baseTypesMap, baseTypesMapDeserialized);} catch (Exception e) {e.printStackTrace();fail();}}
文件方案
將Java對象直接保存到文件中,以及直接從文件中加載內容并轉換為Java對象,可以使用java.io庫中FileInputStream、FileOutputStream來實現。
核心代碼
package org.serialize.serializer;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;public class FileSerialize {public static <T> void serialize(T obj, String fileName) throws Exception {try(FileOutputStream fos = new FileOutputStream(fileName)) {try(ObjectOutputStream oos = new ObjectOutputStream(fos)) {oos.writeObject(obj);oos.flush();}}}public static <T> T deserialize(String fileName) throws Exception {try (FileInputStream fis = new FileInputStream(fileName)) {try (ObjectInputStream ois = new ObjectInputStream(fis)) {@SuppressWarnings("unchecked")T obj = (T) ois.readObject();return obj;}}}}