使用不可序列化的属性序列化Java对象
人們可能有多種原因想要使用自定義序列化而不是依賴Java的默認序列化。 最常見的原因之一是為了提高性能,但是編寫自定義序列化的另一個原因是不支持默認序列化機制。 具體來說,如本博文所述,自定義序列化可用于允許將較大的對象序列化,即使該對象的屬性本身不能直接序列化也是如此 。
下一個代碼清單顯示了一個簡單的類,該類用于將給定類序列化為提供名稱的文件,并從該文件中反序列化對象。 我將在本文中使用它來演示序列化。
SerializationDemonstrator.java
package dustin.examples.serialization;import static java.lang.System.out;import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream;/*** Simple serialization/deserialization demonstrator.* * @author Dustin*/ public class SerializationDemonstrator {/*** Serialize the provided object to the file of the provided name.* @param objectToSerialize Object that is to be serialized to file; it is* best that this object have an individually overridden toString()* implementation as that is used by this method for writing our status.* @param fileName Name of file to which object is to be serialized.* @throws IllegalArgumentException Thrown if either provided parameter is null.*/public static <T> void serialize(final T objectToSerialize, final String fileName){if (fileName == null){throw new IllegalArgumentException("Name of file to which to serialize object to cannot be null.");}if (objectToSerialize == null){throw new IllegalArgumentException("Object to be serialized cannot be null.");}try (FileOutputStream fos = new FileOutputStream(fileName);ObjectOutputStream oos = new ObjectOutputStream(fos)){oos.writeObject(objectToSerialize);out.println("Serialization of Object " + objectToSerialize + " completed.");}catch (IOException ioException){ioException.printStackTrace();}}/*** Provides an object deserialized from the file indicated by the provided* file name.* * @param <T> Type of object to be deserialized.* @param fileToDeserialize Name of file from which object is to be deserialized.* @param classBeingDeserialized Class definition of object to be deserialized* from the file of the provided name/path; it is recommended that this* class define its own toString() implementation as that will be used in* this method's status output.* @return Object deserialized from provided filename as an instance of the* provided class; may be null if something goes wrong with deserialization.* @throws IllegalArgumentException Thrown if either provided parameter is null.*/public static <T> T deserialize(final String fileToDeserialize, final Class<T> classBeingDeserialized){if (fileToDeserialize == null){throw new IllegalArgumentException("Cannot deserialize from a null filename.");}if (classBeingDeserialized == null){throw new IllegalArgumentException("Type of class to be deserialized cannot be null.");}T objectOut = null;try (FileInputStream fis = new FileInputStream(fileToDeserialize);ObjectInputStream ois = new ObjectInputStream(fis)){objectOut = (T) ois.readObject();out.println("Deserialization of Object " + objectOut + " is completed.");}catch (IOException | ClassNotFoundException exception){exception.printStackTrace();}return objectOut;} }下一個代碼清單說明了如何使用SerializationDemonstrator類對標準Java字符串(可序列化)進行序列化和反序列化。 屏幕快照顯示在代碼清單之后,并通過SerializationDemonstrator類的serialize和deserialize serialize方法顯示了運行String的輸出(在NetBeans中)。
在字符串上運行SerializationDemonstrator方法
SerializationDemonstrator.serialize("Inspired by Actual Events", "string.dat"); final String stringOut = SerializationDemonstrator.deserialize("string.dat", String.class);
接下來的兩個代碼清單是針對Person.java類及其作為屬性類型的一個類( CityState.java )。 盡管Person實現了Serializable ,但CityAndState類沒有實現。
人.java
package dustin.examples.serialization;import java.io.Serializable;/*** Person class.* * @author Dustin*/ public class Person implements Serializable {private String lastName;private String firstName;private CityState cityAndState;public Person(final String newLastName, final String newFirstName,final CityState newCityAndState){this.lastName = newLastName;this.firstName = newFirstName;this.cityAndState = newCityAndState;}public String getFirstName(){return this.firstName;}public String getLastName(){return this.lastName;}@Overridepublic String toString(){return this.firstName + " " + this.lastName + " of " + this.cityAndState;} }CityAndState.java
package dustin.examples.serialization;/*** Simple class storing city and state names that is NOT Serializable.* * @author Dustin*/ public class CityState {private final String cityName;private final String stateName;public CityState(final String newCityName, final String newStateName){this.cityName = newCityName;this.stateName = newStateName;}public String getCityName(){return this.cityName;}public String getStateName(){return this.stateName;}@Overridepublic String toString(){return this.cityName + ", " + this.stateName;} }下一個代碼清單演示如何在具有不可序列化的CityState的可序列化Person類上運行SerializationDemonstrator 。 代碼清單后是NetBeans中輸出的屏幕快照。
在具有不可序列化的CityState的可序列化人員上運行SerializationDemonstrator方法
final Person personIn = new Person("Flintstone", "Fred", new CityState("Bedrock", "Cobblestone")); SerializationDemonstrator.serialize(personIn, "person.dat");final Person personOut = SerializationDemonstrator.deserialize("person.dat", Person.class);
在這種情況下, CityState類是我自己的類,可以將其設置為Serializable。 但是,假設該類是第三方框架或庫的一部分,并且我無法更改該類本身,則可以將Person更改為使用自定義序列化和反序列化,并正確使用CityState 。 這在適用于Person的類SerializablePerson的下一個代碼清單中顯示。
SerializablePerson.java
package dustin.examples.serialization;import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamException; import java.io.Serializable;/*** Person class.* * @author Dustin*/ public class SerializablePerson implements Serializable {private String lastName;private String firstName;private CityState cityAndState;public SerializablePerson(final String newLastName, final String newFirstName,final CityState newCityAndState){this.lastName = newLastName;this.firstName = newFirstName;this.cityAndState = newCityAndState;}public String getFirstName(){return this.firstName;}public String getLastName(){return this.lastName;}@Overridepublic String toString(){return this.firstName + " " + this.lastName + " of " + this.cityAndState;}/*** Serialize this instance.* * @param out Target to which this instance is written.* @throws IOException Thrown if exception occurs during serialization.*/private void writeObject(final ObjectOutputStream out) throws IOException{out.writeUTF(this.lastName);out.writeUTF(this.firstName);out.writeUTF(this.cityAndState.getCityName());out.writeUTF(this.cityAndState.getStateName());}/*** Deserialize this instance from input stream.* * @param in Input Stream from which this instance is to be deserialized.* @throws IOException Thrown if error occurs in deserialization.* @throws ClassNotFoundException Thrown if expected class is not found.*/private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException{this.lastName = in.readUTF();this.firstName = in.readUTF();this.cityAndState = new CityState(in.readUTF(), in.readUTF());}private void readObjectNoData() throws ObjectStreamException{throw new InvalidObjectException("Stream data required");} }上面的代碼清單顯示SerializablePerson具有自定義的writeObject和readObject方法,以支持自定義的序列化/反序列化, CityState適當地處理其CityState序列化類型CityState屬性。 接下來顯示用于通過SerializationDemonstrator運行該類的代碼片段以及這樣做的成功輸出。
在SerializablePerson上運行SerializationDemonstrator
final SerializablePerson personIn = new SerializablePerson("Flintstone", "Fred", new CityState("Bedrock", "Cobblestone")); SerializationDemonstrator.serialize(personIn, "person.dat");final SerializablePerson personOut = SerializationDemonstrator.deserialize("person.dat", SerializablePerson.class);
上面描述的方法將允許將不可序列化的類型用作可序列化類的屬性,而無需使那些字段處于瞬態狀態。 但是,如果前面顯示的CityState實例需要在多個可序列化的類中使用,則最好使用可序列化的裝飾器裝飾CityState類,然后在需要序列化的類中使用該序列化的裝飾器類。 下一個代碼清單顯示SerializableCityState ,它用序列化的版本裝飾CityState 。
SerializableCityState
package dustin.examples.serialization;import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamException; import java.io.Serializable;/*** Simple class storing city and state names that IS Serializable. This class* decorates the non-Serializable CityState class and adds Serializability.* * @author Dustin*/ public class SerializableCityState implements Serializable {private CityState cityState;public SerializableCityState(final String newCityName, final String newStateName){this.cityState = new CityState(newCityName, newStateName);}public String getCityName(){return this.cityState.getCityName();}public String getStateName(){return this.cityState.getStateName();}@Overridepublic String toString(){return this.cityState.toString();}/*** Serialize this instance.* * @param out Target to which this instance is written.* @throws IOException Thrown if exception occurs during serialization.*/private void writeObject(final ObjectOutputStream out) throws IOException{out.writeUTF(this.cityState.getCityName());out.writeUTF(this.cityState.getStateName());}/*** Deserialize this instance from input stream.* * @param in Input Stream from which this instance is to be deserialized.* @throws IOException Thrown if error occurs in deserialization.* @throws ClassNotFoundException Thrown if expected class is not found.*/private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException{this.cityState = new CityState(in.readUTF(), in.readUTF());}private void readObjectNoData() throws ObjectStreamException{throw new InvalidObjectException("Stream data required");} }可以直接在Person類中使用此可序列化的修飾器,并且封閉的Person可以使用默認序列化,因為其字段都是可序列化的。 這顯示在Person改編的Person2的下一個代碼清單中。
Person2.java
package dustin.examples.serialization;import java.io.Serializable;/*** Person class.* * @author Dustin*/ public class Person2 implements Serializable {private final String lastName;private final String firstName;private final SerializableCityState cityAndState;public Person2(final String newLastName, final String newFirstName,final SerializableCityState newCityAndState){this.lastName = newLastName;this.firstName = newFirstName;this.cityAndState = newCityAndState;}public String getFirstName(){return this.firstName;}public String getLastName(){return this.lastName;}@Overridepublic String toString(){return this.firstName + " " + this.lastName + " of " + this.cityAndState;} }可以像下面的代碼清單中所示那樣執行該代碼,然后在NetBeans輸出窗口中看到其輸出。
針對Person2 / SerializableCityState運行SerializationDemonstrator
final Person2 personIn = new Person2("Flintstone", "Fred", new SerializableCityState("Bedrock", "Cobblestone")); SerializationDemonstrator.serialize(personIn, "person.dat");final Person2 personOut = SerializationDemonstrator.deserialize("person.dat", Person2.class);
自定義序列化可用于允許對具有不可序列化類型的屬性的類進行序列化,而不會使那些不可序列化類型的屬性瞬變。 當可序列化的類需要使用不可序列化且無法更改的類型的屬性時,這是一種有用的技術。
參考:來自JCG合作伙伴 Dustin Marx在Inspired by Actual Events博客上的使用不可序列化屬性序列化Java對象 。翻譯自: https://www.javacodegeeks.com/2014/02/serializing-java-objects-with-non-serializable-attributes.html
總結
以上是生活随笔為你收集整理的使用不可序列化的属性序列化Java对象的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Spring的Hibernate构建
- 下一篇: ObjectStreamClass:监视