企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 使用`readObject`和`writeObject`的 Java 自定义序列化 > 原文: [https://howtodoinjava.com/java/serialization/custom-serialization-readobject-writeobject/](https://howtodoinjava.com/java/serialization/custom-serialization-readobject-writeobject/) 在某些情况下,您可能需要在 Java 中使用**自定义序列化**。 例如,您有遗留的 Java 类,由于任何原因都不愿意对其进行修改。 也可能存在一些设计约束。 甚至简单地说,该类将在将来的发行版中进行更改,这可能会破坏[先前序列化对象的反序列化](https://howtodoinjava.com/java/serialization/a-mini-guide-for-implementing-serializable-interface-in-java/)。 ```java Table of Contents 1\. Custom Serialization 2\. Default Serialization with Added Validation 3\. Summary ``` ## 1\. Java 自定义序列化 在大多数情况下,当**自定义 Java 序列化**时,您将按顺序逐一写入字段。 它最常用的*方法将覆盖默认的 Java 序列化*进程。 假设我们有一个`User`对象,我们想自定义它的序列化过程。 ```java public class User implements Serializable { private static final long serialVersionUID = 7829136421241571165L; private String firstName; private String lastName; private int accountNumber; private Date dateOpened; public User(String firstName, String lastName, int accountNumber, Date dateOpened) { super(); this.firstName = firstName; this.lastName = lastName; this.accountNumber = accountNumber; this.dateOpened = dateOpened; } public User() { super(); } public final String getFirstName() { return firstName; } public final String getLastName() { return lastName; } public final int getAccountNumber() { return accountNumber; } public final Date getDateOpened() { return new Date(dateOpened.getTime()); } public final void setFirstName(String aNewFirstName) { firstName = aNewFirstName; } public final void setLastName(String aNewLastName) { lastName = aNewLastName; } public final void setAccountNumber(int aNewAccountNumber) { accountNumber = aNewAccountNumber; } public final void setDateOpened(Date aNewDate) { Date newDate = new Date(aNewDate.getTime()); dateOpened = newDate; } } ``` #### 1.1 `readObject()`和`writeObject()`方法 要自定义序列化和反序列化,请在此类中定义`readObject()`和`writeObject()`方法。 * 在`writeObject()`方法内部,使用`ObjectOutputStream`提供的`writeXXX`方法编写类属性。 * 在`readObject()`方法内部,使用`ObjectInputStream`提供的`readXXX`方法读取类属性。 * 请注意,读写方法中类属性的**序列必须与**相同。 ```java import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Date; public class User implements Serializable { private static final long serialVersionUID = 7829136421241571165L; private String firstName; private String lastName; private int accountNumber; private Date dateOpened; public User(String firstName, String lastName, int accountNumber, Date dateOpened) { super(); this.firstName = firstName; this.lastName = lastName; this.accountNumber = accountNumber; this.dateOpened = dateOpened; } public User() { super(); } //Setters and Getters private void readObject(ObjectInputStream aInputStream) throws ClassNotFoundException, IOException { firstName = aInputStream.readUTF(); lastName = aInputStream.readUTF(); accountNumber = aInputStream.readInt(); dateOpened = new Date(aInputStream.readLong()); } private void writeObject(ObjectOutputStream aOutputStream) throws IOException { aOutputStream.writeUTF(firstName); aOutputStream.writeUTF(lastName); aOutputStream.writeInt(accountNumber); aOutputStream.writeLong(dateOpened.getTime()); } } ``` 现在,我们来测试代码。 #### 1.2 测试自定义序列化 ```java package com.howtodoinjava.io.example; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Calendar; import java.util.Date; public class TestCustomSerialization { public static void main(String[] args) { // Create new User object User myDetails = new User("Lokesh", "Gupta", 102825, new Date(Calendar.getInstance().getTimeInMillis())); // Serialization code try { FileOutputStream fileOut = new FileOutputStream("User.ser"); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(myDetails); out.close(); fileOut.close(); } catch (IOException i) { i.printStackTrace(); } // De-serialization code User deserializedUser = null; try { FileInputStream fileIn = new FileInputStream("User.ser"); ObjectInputStream in = new ObjectInputStream(fileIn); deserializedUser = (User) in.readObject(); in.close(); fileIn.close(); // verify the object state System.out.println(deserializedUser.getFirstName()); System.out.println(deserializedUser.getLastName()); System.out.println(deserializedUser.getAccountNumber()); System.out.println(deserializedUser.getDateOpened()); } catch (IOException ioe) { ioe.printStackTrace(); } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); } } } ``` //输出 ```java Lokesh Gupta 102825 Wed May 24 13:05:25 IST 2017 ``` ## 2\. 覆盖默认序列化以添加验证 有时,您可能只需要执行任何特定的验证,或者在反序列化的对象上运行一些业务规则,而不会影响默认的 Java 序列化机制。 当您决定使用`readObject()`和`writeObject()`方法时,这也是可能的。 在此用例中,可以在`readObject()`和`writeObject()`方法中使用`defaultReadObject()`和`defaultWriteObject()` - 启用默认的序列化和反序列化。 然后,您可以将您的*自定义验证*或业务规则插入读/写方法中。 这样,在默认的序列化和反序列化过程发生后,JVM 将立即自动调用验证方法。 ```java public class User implements Serializable { //class attributes, constructors, setters and getters as shown above /** * Always treat de-serialization as a full-blown constructor, by validating the final state of the de-serialized object. */ private void readObject(ObjectInputStream aInputStream) throws ClassNotFoundException, IOException { // perform the default de-serialization first aInputStream.defaultReadObject(); // make defensive copy of the mutable Date field dateOpened = new Date(dateOpened.getTime()); // ensure that object state has not been corrupted or tampered with malicious code //validateUserInfo(); } /** * This is the default implementation of writeObject. Customize as necessary. */ private void writeObject(ObjectOutputStream aOutputStream) throws IOException { //ensure that object is in desired state. Possibly run any business rules if applicable. //checkUserInfo(); // perform the default serialization for all non-transient, non-static fields aOutputStream.defaultWriteObject(); } } ``` 再次测试代码,您将看到以下输出: ```java Lokesh Gupta 102825 Wed May 24 13:10:18 IST 2017 ``` ## 3\. 总结 如我们所见,自定义序列化在 Java 中非常容易,并且涉及非常简单的设计,即实现`readObject()`和`writeObject()`方法; 并添加任何其他逻辑以支持应用程序业务逻辑。 尽管在大多数情况下,默认的序列化/反序列化就足够了; 在需要时仍应在 Java 应用程序中使用自定义序列化。 将我的问题放在评论部分。 学习愉快!