Java 外部化示例 – 更有效的序列化

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 + "]";
	}
}

ExternalizablewriteExternal()示例

writeExternal()方法用于提供序列化逻辑,即将类的字段写入字节。 在读回序列化的对象之后,您可以自由地仅存储要返回的那些字段,忽略其余字段。

public void writeExternal(ObjectOutput out) throws IOException {

	//We are not storing the field 'doNotStoreMe'

	out.writeInt(fieldOne);
	out.writeUTF(fieldTwo);
	out.writeBoolean(fieldThree);
}

ExternalizablereadExternal()示例

唯一需要记住的是 – 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接口的全部目的。

学习愉快!