一、前提
起初看到这个关键字 transient 的时候是在查阅源码 Hashtable 的时候,我们会发现两处声明,如下,一是定义哈希表数据,一是定义哈希表中的条目总数,于是便对该关键字产生了兴趣,此前对此并无太深印象,也未曾使用过,于是便花时间了解了下。
/**
* The hash table data.哈希表数据
*/
private transient Entry<?,?>[] table;
/**
* The total number of entries in the hash table.哈希表中的条目总数
*/
private transient int count;
复制代码
二、transient 的作用以及使用方法
那我们如何才能使用到该关键字呢?这里要引入一个知识:序列化。
序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
那么当我们存在一些对象中包含隐私安全信息类的声明时,比如一些银行卡密码,手机号,身份证,诸如此类,不希望将其在此过程中被传输,那么这种场景下就需要用到 transient 关键字去声明。
/*
*声明一个person对象,password用到关键字transient
*/
public class Person implements Serializable {
public Person(String id,String name,String password){
this.id = id;
this.name = name;
this.password = password;
}
private String id;
private String name;
private transient String password;
//get、set、tostring省略
}
复制代码
public class TestTransient {
public static void main(String[] args) throws Exception{
Person person = new Person("1","oldking","123456");
System.out.println("序列化之前---"+person.toString());
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("c:/test.text"));
os.writeObject(person);
os.flush();
ObjectInputStream oi = new ObjectInputStream(new FileInputStream("c:/test.text"));
Person o = (Person)oi.readObject();
System.out.println("序列化之后---"+o.toString());
}
}
复制代码
运行之后得到的结果:那么我们可以看到读取持久化之后的对象 password 为 null,从而得出反序列化时并没有从持久化文件中得到密码信息。
序列化之前---Person{id='1', name='oldking', password='123456'}
序列化之后---Person{id='1', name='oldking', password='null'
复制代码
三、transient 使用小结
1)一旦变量被 transient 修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
2)transient 关键字只能修饰变量,而不能修饰方法和类。注意,本地变量(局部变量)是不能被 transient 关键字修饰的。变量如果是用户自定义类变量,则该类需要实现 Serializable 接口。
3)被 transient 关键字修饰的变量不再能被序列化,一个静态变量不管是否被 transient 修饰,均不能被序列化。
对于第三点我们来用程序论证一下:
public class Person implements Serializable {
public Person(String id,String name,String password){
this.id = id;
this.name = name;
this.password = password;
}
private String id;
//定义一个静态变量name
public static String name;
private transient String password;
}
复制代码
public class TestTransient {
public static void main(String[] args) throws Exception{
Person person = new Person("1","oldking","123456");
System.out.println("序列化之前---"+person.toString());
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("c:/test.text"));
os.writeObject(person);
os.flush();
ObjectInputStream oi = new ObjectInputStream(new FileInputStream("c:/test.text"));
Person o = (Person)oi.readObject();
Person.name = "阿志";
System.out.println("序列化之后---"+o.toString());
}
}
复制代码
运行之后得到的结果是这样子的,我们发现 name 值是不一样的,跟随的是当前 jvm 对应的值。
序列化之前---Person{id='1', name='oldking', password='123456'}
序列化之后---Person{id='1', name='阿志', password='null'}
复制代码
四、总结
因此,我们知道该关键字 transient 是为了防止对象中的变量序列化时被持久化保存导致的信息泄露以及其他不安全的操作。对于 Hashtable 中的几处定义也存在该关键字,想必目的也是出于此吧。感兴趣的也可以了解下注解 @Transient 可以达到这个目的。
评论