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

> 原文： [https://howtodoinjava.com/java/serialization/java-externalizable-example/](https://howtodoinjava.com/java/serialization/java-externalizable-example/)

默认的 Java 序列化效率不高。 如果您序列化了一个具有许多属性和属性的胖对象，则您不希望出于任何原因进行序列化（例如，它们始终被分配默认值），您将需要处理繁重的对象并通过网络发送更多字节，这在某些情况下可能会非常昂贵。

要解决此问题，您可以通过实现[`Externalizable`](https://docs.oracle.com/javase/7/docs/api/java/io/Externalizable.html)接口并覆盖其方法`writeExternal()`和`readExternal()`来编写自己的序列化逻辑。 通过实现这些方法，您将告诉 JVM 如何编码/解码对象。

出于示例目的，我创建了这个简单的类，我们将使用`writeExternal()`和`readExternal()`方法进行序列化和反序列化。

```java
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()`](https://docs.oracle.com/javase/7/docs/api/java/io/Externalizable.html#writeExternal%28java.io.ObjectOutput%29)方法用于提供序列化逻辑，即将类的字段写入字节。 在读回序列化的对象之后，您可以自由地仅存储要返回的那些字段，忽略其余字段。

```java
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()`](https://docs.oracle.com/javase/7/docs/api/java/io/Externalizable.html#readExternal%28java.io.ObjectInput%29)方法必须读取与`writeExternal()`写入的序列相同且类型相同的值。

```java
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
	fieldOne = in.readInt();
	fieldTwo = in.readUTF();
	fieldThree = in.readBoolean();
}

```

## 完整的例子

现在，让我们编写代码进行序列化并读回字节，以验证 JVM 是否遵守契约。

```java
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();
        }
	}
}

```

```java
Output:

UserSettings [doNotStoreMe=Sensitive info, fieldOne=10000, fieldTwo=HowToDoInJava.com, fieldThree=false]
UserSettings [doNotStoreMe=null, fieldOne=10000, fieldTwo=HowToDoInJava.com, fieldThree=false]
```

显然，我们可以取回所需的字段，而忽略不需要的字段，这就是`Externalizable`接口的全部目的。

学习愉快！