在许多情况下,您可能需要在 java 中自定义序列化。例如,您有遗留的 Java 类,您出于任何原因都不愿意对其进行修改。也可能存在一些设计限制。或者甚至简单地说,该类预计会在未来的版本中发生变化,这可能会破坏先前序列化对象的反序列化 .
在大多数情况下,当您自定义 java 序列化时,您将按顺序一个接一个地编写字段。它是覆盖默认 java 序列化 进程的最常见方式。
比方说,我们有一个 User
对象,我们想要自定义它的序列化过程。
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; } }
要自定义序列化和反序列化,请在此类中定义 readObject()
和 writeObject()
方法。
writeObject()
方法中,使用ObjectOutputStream
提供的writeXXX
方法写入类属性。readObject()
方法中,使用ObjectInputStream
提供的readXXX
方法读取类属性。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()); } }
现在让我们测试代码。
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(); } } }
//输出
Lokesh Gupta 102825 Wed May 24 13:05:25 IST 2017
有时您可能需要只执行任何特定的验证,或者在反序列化对象上运行一些业务规则——而不影响默认的 java 序列化机制。当您决定使用 readObject()
和 writeObject()
方法时,这也是可能的。
在此用例中,您可以在 readObject()
和 writeObject()
中使用 defaultReadObject()
和 defaultWriteObject()
方法——启用默认序列化和反序列化。然后,您可以在读/写方法中插入自定义验证或业务规则。 这样,JVM 将在默认序列化和反序列化过程发生后立即自动调用您的验证方法。
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(); } }
再次测试代码,您将看到以下输出:
Lokesh Gupta 102825 Wed May 24 13:10:18 IST 2017
正如我们所见,自定义序列化在 Java 中非常容易,它涉及非常简单的设计,即实现 readObject()
和 writeObject()
方法;并添加任何额外的逻辑来支持应用程序业务逻辑。
尽管在大多数情况下默认序列化/反序列化就足够了;仍然需要时,您应在 Java 应用程序中使用自定义序列化。
在评论部分把你的问题告诉我。
快乐学习!!
地址:https://www.cundage.com/article/custom-serialization-readobject-writeobject.html