transient关键字详解transient关键字详解
1:用途:
我们知道,当一个对象实现了Serilizable接口,这个对象就可以被序列化,我们不关心其内在的原理,只需要了解这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化。而在开发过程中,我们可能要求:当对象被序列化时(写入字节序列到目标文件)时,有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输,这些信息对应的变量就可以加上transient关键字。换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。
所以,transient的用途在于:阻止实例中那些用此关键字声明的变量持久化;当对象被反序列化时(从源文件读取字节序列进行重构),这样的实例变量值不会被持久化和恢复。例如,当反序列化对象——数据流(例如,文件)可能不存在时,原因是你的对象中存在类型为java.io.InputStream的变量,序列化时这些变量引用的输入流无法被打开。
2:使用方法:
序列化的时候,将不需要序列化的属性前添加关键字transient即可。
示例:
1 package com.springboot.study.tests; 2 3 import lombok.Data; 4 5 import java.io.*; 6 7 /** 8 * @Author: guodong 9 * @Date: 2021/2/4 10:38 10 * @Version: 1.0 11 * @Description: 12 */ 13 public class TestTransient { 14 15 public static void main(String[] args) { 16 UserInfo userInfo = new UserInfo("张三", "123456"); 17 System.out.println(userInfo); 18 try { 19 // 序列化,被设置为transient的属性没有被序列化 20 ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.txt")); 21 o.writeObject(userInfo); 22 o.close(); 23 } catch (Exception e) { 24 // TODO: handle exception 25 e.printStackTrace(); 26 } 27 28 try { 29 // 重新读取内容 30 ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.txt")); 31 UserInfo readUserInfo = (UserInfo) in.readObject(); 32 //读取后psw的内容为null 33 System.out.println(readUserInfo.toString()); 34 } catch (Exception e) { 35 // TODO: handle exception 36 e.printStackTrace(); 37 } 38 } 39 40 } 41 42 43 @Data 44 class UserInfo implements Serializable { 45 46 private static final long serialVersionUID = 996890129747019948L; 47 48 private String name; 49 50 private transient String psw; 51 52 public UserInfo(String name, String psw) { 53 this.name = name; 54 this.psw = psw; 55 } 56 57 public String toString() { 58 return "name=" + name + ", psw=" + psw; 59 } 60 61 }
运行结果如下图所示:
name=张三, psw=123456 name=张三, psw=null
密码字段为null,说明被标记为transient的属性在对象被序列化的时候不会被保存。
使用小结:
1,一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
2,transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
3,被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。
对于第三点,加上static之后,依然能把姓名输出。这是因为:反序列化后类中static型变量name的值为当前JVM中对应static变量的值,这个值是JVM中的不是反序列化得出的。下例可说明,其值时JVM中得到的而不是反序列化得到的:
1 package com.springboot.study.tests; 2 3 import lombok.AllArgsConstructor; 4 import lombok.Data; 5 import lombok.NoArgsConstructor; 6 import lombok.ToString; 7 8 import java.io.*; 9 10 /** 11 * @Author: guodong 12 * @Date: 2021/2/4 10:38 13 * @Version: 1.0 14 * @Description: 15 */ 16 @Data 17 @NoArgsConstructor 18 @AllArgsConstructor 19 class UserInfo implements Serializable { 20 private static final long serialVersionUID = 996890129747019948L; 21 private static String name; 22 private transient String psw; 23 24 public static String getName() { 25 return name; 26 } 27 28 public static void setName(String name) { 29 UserInfo.name = name; 30 } 31 32 public void setPsw(String psw) { 33 this.psw = psw; 34 } 35 36 @Override 37 public String toString() { 38 return "name=" + name + ", psw=" + psw; 39 } 40 } 41 42 43 public class TestTransient { 44 public static void main(String[] args) { 45 UserInfo userInfo = new UserInfo(); 46 userInfo.setPsw("25657"); 47 userInfo.setName("张6三"); 48 System.out.println(userInfo); 49 try { 50 // 序列化,被设置为transient的属性没有被序列化 51 ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.txt")); 52 o.writeObject(userInfo); 53 o.close(); 54 } catch (Exception e) { 55 // TODO: handle exception 56 e.printStackTrace(); 57 } 58 try { 59 //在反序列化之前改变name的值 60 userInfo.setName("hello"); 61 // 重新读取内容 62 ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.txt")); 63 UserInfo readUserInfo = (UserInfo) in.readObject(); 64 //读取后psw的内容为null 65 System.out.println(readUserInfo.toString()); 66 } catch (Exception e) { 67 // TODO: handle exception 68 e.printStackTrace(); 69 } 70 } 71 72 }
运行结果如下所示:
name=张6三, psw=25657 name=hello, psw=null
这说明反序列化后类中static型变量name的值为当前JVM中对应static变量的值,为修改后hello,而不是序列化时的值“张6三”,也就是说静态变量是无法进行序列化的,在反序列前如果修改对象的值(静态变量的值),则打印结果会变成修改后的值,那序列化就没有意义了,所以注意一下,静态变量无法序列化。