序列化是指將對象轉換為可存儲或可傳輸的格式的過程。在計算機科學中,序列化常用於在進程之間傳輸數據,或將數據存儲到文件或數據庫中。
一、實體類序列化的作用
在Java中,實體類對象是存放在內存中的,而我們需要將其保存到數據庫中或進行網絡傳輸時,則需要將實體類序列化為字節流。
例如,下面是一個用戶實體類的定義:
public class User { private Long id; private String name; private String email; // 構造函數和get/set方法省略 }
將用戶實體類序列化為字節流的示例代碼如下:
User user = new User(1L, "Alice", "alice@example.com"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bos); out.writeObject(user); byte[] bytes = bos.toByteArray(); out.close(); bos.close();
從字節流中反序列化為實體類對象的示例代碼如下:
byte[] bytes = ...; // 從網絡或文件中讀取的字節流 ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream in = new ObjectInputStream(bis); User user = (User) in.readObject(); in.close(); bis.close();
二、序列化活動的概念
1. 序列化和反序列化過程
序列化是將對象轉換為字節流的過程,而反序列化則是將字節流轉換回原始對象的過程。
在Java中,序列化和反序列化可以通過實現Serializable接口來實現。例如:
public class User implements Serializable { ... }
當序列化一個實現Serializable接口的對象時,Java會保存對象的類名、類結構和對象數據等信息,以便在反序列化時使用。
2. 序列化協議
序列化協議是指序列化對象時規定的字節序、類型信息、字段順序等規則。Java有自己的默認序列化協議,也可以使用其它協議,例如Google的Protocol Buffer。
默認情況下,Java使用的序列化協議會將對象數據編碼為字節流,並保存對象的完整類名、字段名稱和類型信息等。這種序列化方式會佔用大量空間,並且對於字段名稱的修改、添加或刪除等操作會造成反序列化失敗。
因此,為了提高序列化的效率和可靠性,我們可以使用優化過的序列化協議,例如Google的Protocol Buffer或Facebook的Thrift。
3. 序列化版本號
序列化版本號是一個32位的整數,用於標識序列化對象的版本號。當對象發生變化時,我們需要更新版本號,以便反序列化時能夠識別出不同版本的對象。
在Java中,可以使用serialVersionUID屬性來表示序列化對象的版本號。例如:
public class User implements Serializable { private static final long serialVersionUID = 1L; ... }
三、與序列化相關的其他概念
1. 反序列化漏洞
反序列化漏洞是指攻擊者利用序列化和反序列化機制的漏洞,將惡意代碼注入到反序列化的對象中,從而導致安全漏洞。這種漏洞通常會導致遠程代碼執行、拒絕服務、數據泄露等嚴重後果。
為了防止反序列化漏洞,我們需要使用白名單機制來限制反序列化的類和對象,或使用安全的序列化協議。
2. JSON序列化
JSON是一種輕量級的數據交換格式,能夠表示複雜的數據結構,並且具有良好的可讀性和易用性。在前後端數據傳輸和API調用中,JSON已經成為了一種標準的編碼方式。
在Java中,我們可以使用Jackson、Gson等庫來將Java對象序列化為JSON字符串,或將JSON字符串反序列化為Java對象。
例如,將User對象序列化為JSON字符串的示例代碼如下:
User user = new User(1L, "Alice", "alice@example.com"); ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(user);
從JSON字符串反序列化為User對象的示例代碼如下:
String json = ...; // 從前端或API獲取的JSON字符串 ObjectMapper mapper = new ObjectMapper(); User user = mapper.readValue(json, User.class);
3. XML序列化
XML是一種用於數據交換的標記語言,具有良好的可擴展性和可讀性。在Java中,我們可以使用JAXB、Xstream等庫將Java對象序列化為XML文件或字符串,或將XML字符串反序列化為Java對象。
例如,將User對象序列化為XML文件的示例代碼如下:
User user = new User(1L, "Alice", "alice@example.com"); JAXBContext context = JAXBContext.newInstance(User.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(user, new File("user.xml"));
從XML文件中反序列化為User對象的示例代碼如下:
File file = new File("user.xml"); // 從文件中讀取XML數據 JAXBContext context = JAXBContext.newInstance(User.class); Unmarshaller unmarshaller = context.createUnmarshaller(); User user = (User) unmarshaller.unmarshal(file);
4. 序列化框架
隨着業務系統的複雜度不斷提高,我們需要處理更加複雜的數據結構和業務邏輯。因此,序列化框架成為了一個重要的工具和組件庫。
目前流行的Java序列化框架包括Kryo、FST、Hessian、Avro等。這些框架具有高效、可擴展、易用等特點,並且可以適應不同的業務場景和性能需求。
例如,使用Kryo將User對象序列化為字節流的示例代碼如下:
User user = new User(1L, "Alice", "alice@example.com"); Kryo kryo = new Kryo(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); Output output = new Output(bos); kryo.writeObject(output, user); output.close(); byte[] bytes = bos.toByteArray(); bos.close();
從字節流反序列化為User對象的示例代碼如下:
byte[] bytes = ...; // 從網絡或文件中讀取的字節流 Kryo kryo = new Kryo(); Input input = new Input(bytes); User user = kryo.readObject(input, User.class); input.close();
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/186245.html