2022年1月3日 星期一

Java 物件序列化 (Object Serialize/Deserializ)

Java 可以使用序列化/反序列化的技術將物件實體 (Object Instance) 
轉成位元組格式資料 (通常用 byte array 表示) 再轉回來,
方便我們將物件實體保持起來等之後將其還原回物件實體,
或將其轉文字等用 http request 送給其他 server 並在server 端接收並還原。

Note:

物件必須要實作 Serializable 介面才能被序列化。
這篇文紀錄下 Java  如何物件的序列化(Serialize)/反序列化(Deserialize),
以下程式碼展示了兩個範例,
分別為將物件以檔案的方式
及以文字的方式進行序列化/反序列化。

而不管是將物件序列化成何種型式(例如檔案或文字),
概念都是一樣的,就是以物件被序列化成位元組格式
及將位元組反序列化回物件。

需要注意的是,如果想將物件序列化成文字 (String) 的話,
因為位元組轉成文字後,有可能會因為編碼等問題轉不回原來的位元組資料,
這時可先將位元組資料用例如 Base64 編碼得到字串來當做序列化後的字串保存起來,
之後要反序列化回物件時,把字串用 Base64 解碼成位元組格式,
再將位元組格式的資料反序列化回物件即可。

以下為程式碼範例 (jdk-11):

先建一個簡單的測試用 Class, Person.java:
Person.java:
package myTest;

import java.io.Serializable;

public class Person implements Serializable{
	private static final long serialVersionUID = 1L;
	
	private String name;
	
	public Person(String name) {
		this.name = name;
	}
	
	public void sayHello() {
		System.out.println("Hello, I'm " + name + ".");
	}
}

再來是序列化/反序列化的程式碼:
TestObjectSerialize.java:
package myTest;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Base64;

public class TestObjectSerialize {

	public static void main(String[] args) {
		Person person = new Person("Hugo");
		person.sayHello(); //Hello, I'm Hugo.
		
		writeObjectToFile(person, "D:\\MyClass");
		Person deSerializedObject = readObjectFromFile(Person.class, "D:\\MyClass");
		deSerializedObject.sayHello(); //Hello, I'm Hugo.
		
		String serializedObjectString = writeObjectToString(person);
		Person deSerializedObject2 = readObjectFromString(Person.class, serializedObjectString);
		deSerializedObject2.sayHello(); //Hello, I'm Hugo.
		
		System.out.println("Done");
	}
	
	//----- Serialize/Desrialize Object through file -----//
	public static <T> void writeObjectToFile(T object, String filePath){
		try (FileOutputStream fileOutputStream = new FileOutputStream(filePath);
			 ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);){
			
			objectOutputStream.writeObject(object);
		}catch(IOException e) {
			e.printStackTrace();
		}
	}
	
	public static <T> T readObjectFromFile(Class<T> clazz, String filePath){
		T deserializedObject = null;
		
		try (
				FileInputStream fileInputStream = new FileInputStream(filePath);
				ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
			){
			
			deserializedObject = (T) objectInputStream.readObject();
		}catch(IOException | ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		return deserializedObject;
	}
	
	//----- Serialize/Desrialize Object through String -----//
	//Because Object can be serilaized to String
	//, the String can stored in anywhere or be transfer to other server 
	//and be deserialized to original Object from String.
	//Notice: After serializing Object to Byte Array, you should use some way like Base64Encoding to
	//encode the Byte Array to String,
	//because the String you got directly from Byte Array might not be transfered to original Byte Array.
	public static <T> String writeObjectToString(T object){
		String serializedObjectString = "";

		try (
				ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
				ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
			){
			
			objectOutputStream.writeObject(object);
			serializedObjectString = new String(Base64.getEncoder().encode(byteArrayOutputStream.toByteArray()), "UTF-8");
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
		return serializedObjectString;
	}
	
	public static <T> T readObjectFromString(Class<T> clazz, String serializedObjectString){
		T deserializedObject = null;
		
		try (
				ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(Base64.getDecoder().decode(serializedObjectString.getBytes("UTF-8")));
				ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
			){
			
			deserializedObject = (T) objectInputStream.readObject();
		} catch (IOException | ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		return deserializedObject;
	}

}

沒有留言 :

張貼留言