当我们序列化进行控制时,可能存在某个特定子对象不想让 Java 的序列化机制自动保存与
恢复。如果子对象表示的是我们不想序列化的敏感信息(如密码),通常就会面临这种情况。
即使对象中的这些信息是“private”(私有)属性,一经序列化处理,人们就可以通过读取
文件,或者拦截网络传输的方式来访问到它。
有一种防止对象的敏感部分被序列化的办法,就是将我们自己的类实现为 Externalizable,
如前面所示。这样一来,没有任何东西可以自动序列化,并且我们可以在 writeExternal()
内部只对所需部分进行显式的序列化。
然而,如果我们正在操作的是一个 Serializable 对象,那么所有序列化操作都会自动进行。
为了能够予以控制,可以用 transient(瞬时)关键字逐个域地关闭序列化,它意旨“不用
麻烦你保存或恢复数据——我自己会处理的”。
例如,假设某个 Login 对象保存某个特定的登录会话信息。登录的合法性通过校验之后,
我们想把数据保存下来,但不包括密码。为做到这一点,最简单的办法是实现 Serializable,
并将 password 域标志为 transient。下面是具体的代码:
//: c12:Logon.java
// Demonstrates the "transient" keyword.
// {Clean: Logon.out}
import java.io.*;
import java.util.*;
public class Logon implements Serializable {
private Date date = new Date();
private String username;
private transient String password;
public Logon(String name, String pwd) {
username = name;
password = pwd;
}
public String toString() {
String pwd = (password == null) ? "(n/a)" : password;
return "logon info: \n username: " + username +
"\n date: " + date + "\n password: " + pwd;
}
public static void main(String[] args) throws Exception {
Logon a = new Logon("Hulk", "myLittlePony");
System.out.println( "logon a = " + a);
ObjectOutputStream o = new ObjectOutputStream(
new FileOutputStream("Logon.out"));
o.writeObject(a);
o.close();
Thread.sleep(1000); // Delay for 1 second
// Now get them back:
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("Logon.out"));
System.out.println("Recovering object at "+new Date());
a = (Logon)in.readObject();
System.out.println("logon a = " + a);
}
} ///:~
我们可以看到,其中的 date 和 username 域是一般数据(不是 transient),所以它们会
被自动序列化。而 password 是 transient,所以不会被自动保存到磁盘;另外,自动序列
化机制也不会尝试去恢复它。输出如下:
logon a = logon info:
username: Hulk
date: Mon Oct 21 12:10:13 MDT 2002
password: myLittlePony
Recovering object at Mon Oct 21 12:10:14 MDT 2002
logon a = logon info:
username: Hulk
date: Mon Oct 21 12:10:13 MDT 2002
password: (n/a)
当对象被恢复时,password 域就会变成 null。注意必须用 toString()检查 password 是
否为 null,因为如果用重载的“+”运算符来连接 String 对象,并且该运算符如果遇到一个
null 引用,我们就会得到 NullPointerException 异常(新版 Java 可能会包含避免这个问
题的代码)。
我们还可以发现:date 域被存储了到磁盘并从磁盘上被恢复了出来,而且没有再重新生成。
由于 Externalizable 对象在缺省情况下不保存它们的任何域,所以 transient 关键字只能
恢复。如果子对象表示的是我们不想序列化的敏感信息(如密码),通常就会面临这种情况。
即使对象中的这些信息是“private”(私有)属性,一经序列化处理,人们就可以通过读取
文件,或者拦截网络传输的方式来访问到它。
有一种防止对象的敏感部分被序列化的办法,就是将我们自己的类实现为 Externalizable,
如前面所示。这样一来,没有任何东西可以自动序列化,并且我们可以在 writeExternal()
内部只对所需部分进行显式的序列化。
然而,如果我们正在操作的是一个 Serializable 对象,那么所有序列化操作都会自动进行。
为了能够予以控制,可以用 transient(瞬时)关键字逐个域地关闭序列化,它意旨“不用
麻烦你保存或恢复数据——我自己会处理的”。
例如,假设某个 Login 对象保存某个特定的登录会话信息。登录的合法性通过校验之后,
我们想把数据保存下来,但不包括密码。为做到这一点,最简单的办法是实现 Serializable,
并将 password 域标志为 transient。下面是具体的代码:
//: c12:Logon.java
// Demonstrates the "transient" keyword.
// {Clean: Logon.out}
import java.io.*;
import java.util.*;
public class Logon implements Serializable {
private Date date = new Date();
private String username;
private transient String password;
public Logon(String name, String pwd) {
username = name;
password = pwd;
}
public String toString() {
String pwd = (password == null) ? "(n/a)" : password;
return "logon info: \n username: " + username +
"\n date: " + date + "\n password: " + pwd;
}
public static void main(String[] args) throws Exception {
Logon a = new Logon("Hulk", "myLittlePony");
System.out.println( "logon a = " + a);
ObjectOutputStream o = new ObjectOutputStream(
new FileOutputStream("Logon.out"));
o.writeObject(a);
o.close();
Thread.sleep(1000); // Delay for 1 second
// Now get them back:
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("Logon.out"));
System.out.println("Recovering object at "+new Date());
a = (Logon)in.readObject();
System.out.println("logon a = " + a);
}
} ///:~
我们可以看到,其中的 date 和 username 域是一般数据(不是 transient),所以它们会
被自动序列化。而 password 是 transient,所以不会被自动保存到磁盘;另外,自动序列
化机制也不会尝试去恢复它。输出如下:
logon a = logon info:
username: Hulk
date: Mon Oct 21 12:10:13 MDT 2002
password: myLittlePony
Recovering object at Mon Oct 21 12:10:14 MDT 2002
logon a = logon info:
username: Hulk
date: Mon Oct 21 12:10:13 MDT 2002
password: (n/a)
当对象被恢复时,password 域就会变成 null。注意必须用 toString()检查 password 是
否为 null,因为如果用重载的“+”运算符来连接 String 对象,并且该运算符如果遇到一个
null 引用,我们就会得到 NullPointerException 异常(新版 Java 可能会包含避免这个问
题的代码)。
我们还可以发现:date 域被存储了到磁盘并从磁盘上被恢复了出来,而且没有再重新生成。
由于 Externalizable 对象在缺省情况下不保存它们的任何域,所以 transient 关键字只能
和 Serializable 对象一起使用。