transient关键字
1、概述
大家好,我是欧阳方超。
如果某类中的sensitive字段不想被序列化。可以使用transient关键字修饰该字段,则其值不会被序列化。今天就来看看这个问题。
2、transient 关键字
2.1、transient基本概念
transient 关键字是 Java 语言中的一个修饰符,它可以用来修饰类中的实例变量,表示该变量在进行对象序列化时应该被忽略,不会被保存到序列化的结果中。在反序列化时,该变量会被赋值为变量类型的默认值。
transient关键字可以用于阻止特定字段被序列化。当一个对象被序列化时,transient字段的值不会被保存,所以反序列化后,transient字段的值会被重新初始化(基本类型会设为默认值,对象类型会设为null)。
2.2、transient 关键字的应用案例
在Java中,transient关键字用于标记一个类的成员变量,表示这个变量在序列化过程中不需要被保存。这通常用于标记一些敏感信息,例如密码或密钥,以确保它们不会在序列化后泄露。下面是一个示例:
import java.io.Serializable;
public class User implements Serializable {
private String username;
private transient String password; // 标记为transient字段
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
import java.io.*;
public class Main {
public static void main(String[] args) {
User user = new User("tom", "passwrd");
try {
FileOutputStream fileOutputStream = new FileOutputStream("D:\\home\\user.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(user);
objectOutputStream.close();
System.out.println("Serialized data is saved in user.txt");
} catch (IOException e) {
e.printStackTrace();
}
try {
FileInputStream fileInputStream = new FileInputStream("D:\\home\\user.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
user = (User)objectInputStream.readObject();
System.out.println("username: " + user.getUsername());
System.out.println("password: " + user.getPassword());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
上面的程序运行结果为:
Serialized data is saved in user.txt
username: tom
password: null
在上面的示例中,User类实现了Serializable接口,并将password字段标记为transient。在默认情况下,Java的序列化机制只会将非transient字段写入到输出流中,以便在反序列化时恢复对象的状态。因此,如果您有一个transient字段,它将不会被序列化和反序列化,也不会被写入到Java的输出流中。所以在反序列化时password输出的结果为null。
2.3、一个反例
transient修饰的成员变量一定不会被序列化吗?一般情况下是不会被序列化的,然而,可以通过自定义序列化和反序列化方法来手动保存和恢复transient字段的值。在序列化方法中,您可以手动将transient字段的值写入到输出流中(通过 writeObject()方法),而在反序列化方法中,可以手动从输入流中读取transient字段的值(通过readObject()方法)并将其设置回对象中(否则,该字段的值可能会保持null或默认值)。情况下面的代码的运行结果:
import java.io.IOException;
import java.io.Serializable;
public class User implements Serializable {
private String username;
private transient String password; // 标记为transient字段
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
// 在序列化过程中,手动保存password字段
out.writeObject(password);
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
// 在反序列化过程中,手动恢复password字段
password = (String) in.readObject();
}
}
import java.io.*;
public class Main {
public static void main(String[] args) {
User user = new User("tom", "passwrd");
try {
FileOutputStream fileOutputStream = new FileOutputStream("D:\\home\\user.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(user);
objectOutputStream.close();
System.out.println("Serialized data is saved in user.txt");
} catch (IOException e) {
e.printStackTrace();
}
try {
FileInputStream fileInputStream = new FileInputStream("D:\\home\\user.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
user = (User)objectInputStream.readObject();
System.out.println("username: " + user.getUsername());
System.out.println("password: " + user.getPassword());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
运行结果为:
Serialized data is saved in user.txt
username: tom
password: passwrd
可以看到虽然password字段使用了transient来修饰,但依然序列化到了文件并从文件恢复出来了,这就是因为我们在User类中自定义了writeObject()方法和readObject()方法,这两个方法起的作用分别是在序列化时将password字段进行保存、在反序列化时将password字段进行恢复。
3、总结
在Java中,transient关键字用于标记一个类的成员变量,表示这个变量在序列化过程中不需要被保存。这通常用于标记一些敏感信息,例如密码或密钥,以确保它们不会在序列化后泄露。注意,通过相关方法(writeObject()、readObject())依然能够将transient成员变量进行序列化和反序列化,其实,如果要实现对特定字段进行精确地序列化及反序列化,可以使用Externalizable接口,Externalizable接口是一种更高级别的序列化接口,它允许您更精确地控制对象的序列化和反序列化过程,详情我们下次见。我是欧阳方超,把事情做好了自然就有兴趣了,如果你喜欢我的文章,欢迎点赞、转发、评论加关注。