Java 外部化示例 – 更有效的序列化
原文: https://howtodoinjava.com/java/serialization/java-externalizable-example/
默认的 Java 序列化效率不高。 如果您序列化了一个具有许多属性和属性的胖对象,则您不希望出于任何原因进行序列化(例如,它们始终被分配默认值),您将需要处理繁重的对象并通过网络发送更多字节,这在某些情况下可能会非常昂贵。
要解决此问题,您可以通过实现Externalizable
接口并覆盖其方法writeExternal()
和readExternal()
来编写自己的序列化逻辑。 通过实现这些方法,您将告诉 JVM 如何编码/解码对象。
出于示例目的,我创建了这个简单的类,我们将使用writeExternal()
和readExternal()
方法进行序列化和反序列化。
class UserSettings implements Externalizable {
//This is required
public UserSettings(){
}
private String doNotStoreMe;
private Integer fieldOne;
private String fieldTwo;
private boolean fieldThree;
public String getDoNotStoreMe() {
return doNotStoreMe;
}
public void setDoNotStoreMe(String doNotStoreMe) {
this.doNotStoreMe = doNotStoreMe;
}
public Integer getFieldOne() {
return fieldOne;
}
public void setFieldOne(Integer fieldOne) {
this.fieldOne = fieldOne;
}
public String getFieldTwo() {
return fieldTwo;
}
public void setFieldTwo(String fieldTwo) {
this.fieldTwo = fieldTwo;
}
public boolean isFieldThree() {
return fieldThree;
}
public void setFieldThree(boolean fieldThree) {
this.fieldThree = fieldThree;
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
fieldOne = in.readInt();
fieldTwo = in.readUTF();
fieldThree = in.readBoolean();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(fieldOne);
out.writeUTF(fieldTwo);
out.writeBoolean(fieldThree);
}
@Override
public String toString() {
return "UserSettings [doNotStoreMe=" + doNotStoreMe + ", fieldOne="
+ fieldOne + ", fieldTwo=" + fieldTwo + ", fieldThree="
+ fieldThree + "]";
}
}
Externalizable
的writeExternal()
示例
writeExternal()
方法用于提供序列化逻辑,即将类的字段写入字节。 在读回序列化的对象之后,您可以自由地仅存储要返回的那些字段,忽略其余字段。
public void writeExternal(ObjectOutput out) throws IOException {
//We are not storing the field 'doNotStoreMe'
out.writeInt(fieldOne);
out.writeUTF(fieldTwo);
out.writeBoolean(fieldThree);
}
Externalizable
的readExternal()
示例
唯一需要记住的是 – readExternal()
方法必须读取与writeExternal()
写入的序列相同且类型相同的值。
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
fieldOne = in.readInt();
fieldTwo = in.readUTF();
fieldThree = in.readBoolean();
}
完整的例子
现在,让我们编写代码进行序列化并读回字节,以验证 JVM 是否遵守契约。
public class ExternalizableExample
{
public static void main(String[] args)
{
UserSettings settings = new UserSettings();
settings.setDoNotStoreMe("Sensitive info");
settings.setFieldOne(10000);
settings.setFieldTwo("HowToDoInJava.com");
settings.setFieldThree(false);
//Before
System.out.println(settings);
storeUserSettings(settings);
UserSettings loadedSettings = loadSettings();
System.out.println(loadedSettings);
}
private static UserSettings loadSettings() {
try {
FileInputStream fis = new FileInputStream("object.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
UserSettings settings = (UserSettings) ois.readObject();
ois.close();
return settings;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
private static void storeUserSettings(UserSettings settings)
{
try {
FileOutputStream fos = new FileOutputStream("object.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(settings);
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Output:
UserSettings [doNotStoreMe=Sensitive info, fieldOne=10000, fieldTwo=HowToDoInJava.com, fieldThree=false]
UserSettings [doNotStoreMe=null, fieldOne=10000, fieldTwo=HowToDoInJava.com, fieldThree=false]
显然,我们可以取回所需的字段,而忽略不需要的字段,这就是Externalizable
接口的全部目的。
学习愉快!