Java中的transient关键字解析
作者:光与热
transient关键字
java对象在实现了Serilizable接口后这个对象就可以被序列化,但是java的这种序列化机制会将这个类的所有属性和方法都序列化.有时候我们的一些敏感信息比如密码并不想序列化传输给对方,这个时候transient关键字就派上用场了,如果一个类的变量加上了transient关键字那么这个字段就不会被序列化
下面这个例子我们利用transient避免User序列化过程中密码字段的序列化
@Data @ToString @AllArgsConstructor public class User implements Serializable { private String username; private transient String password; }
我们首先创建一个对象User,利用ObjectOutputStream序列化到本地文件,利用ObjectInputStream读取并反序列化为User对象
try (ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("user.txt")); ObjectInputStream is = new ObjectInputStream(new FileInputStream("user.txt"));) { User user = new User("jack", "123456"); System.out.println(user); os.writeObject(user); os.flush(); user = (User) is.readObject(); System.out.println(user); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }
运行结果如下
User{username='jack', password='123456'}
User{username='jack', password='null'}
可以看到密码字段为空
从上面这个例子可以看到一旦变量被transient关键字修饰,该变量就不参与持久化过程,再进一步深入学习transient
1. transient关键字只能修饰变量,不能修饰方法和类.如果变量类型是我们自定义的类,那么这个类需要实现Serializable接口
2. 静态变量无论是否被transient关键字修饰都不参与序列化
接下来我们详细讲解下上述的第二点 我们给User添加一个字段Country,这是一个静态字段
我们重试上面的过程
try (ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("user.txt")); ObjectInputStream is = new ObjectInputStream(new FileInputStream("user.txt"));) { User user = new User("jack", "123456"); User.setCountry("China"); System.out.println(user); os.writeObject(user); os.flush(); user = (User) is.readObject(); System.out.println(user); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }
与第一个例子不同点在于我们在利用setter设置Country
运行结果
User{username='jack', password='123456', country='China'}
User{username='jack', password='null', country='China'}
我们发现country好像被序列化了,但是静态变量无论如何都不参与初始化的,我们猜想country中的值是jvm中的而不是反序列化出来的 我们利用下面这个例子验证我们的猜想
try (ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("user.txt")); ObjectInputStream is = new ObjectInputStream(new FileInputStream("user.txt"));) { User user = new User("jack", "123456"); User.setCountry("China"); System.out.println(user); os.writeObject(user); os.flush(); User.setCountry("American"); user = (User) is.readObject(); System.out.println(user); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }
对象序列化写入文件后我们再修改User的country字段为American
结果如下
User{username='jack', password='123456', country='China'}
User{username='jack', password='null', country='American'}
可以看到country果然变成了American我们的猜想成立,也就是说反序列化后static型变量的值为JVM中的值
还有一点关于transient关键字失灵的情况需要注意,看下面这个例子
@ToString @AllArgsConstructor @NoArgsConstructor public class Student implements Externalizable { private transient String username; private transient int age; private transient String fatherName; @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(username); out.writeInt(age); out.writeObject(fatherName); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { username = (String) in.readObject(); age = in.readInt(); fatherName= (String) in.readObject(); } }
student学生类实现了Externalizable接口作用我们下面再讲,student的所有属性都使用transient关键字修饰
测试代码如下
try (ObjectInput in = new ObjectInputStream(new FileInputStream(new File("student.txt"))); ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File("student.txt")));) { Student student = new Student("student", 20, "father"); System.out.println(student); out.writeObject(student); out.flush(); student = (Student) in.readObject(); System.out.println(student); } catch (Exception e) { e.printStackTrace(); }
运行结果如下所示
Student(username=student, age=20, fatherName=father)
Student(username=student, age=20, fatherName=father)
可以看到尽管transient关键字修饰了所有属性,按理这些属性都不应该被序列化,这是为什么呢,这要谈到java的序列化机制了,java自带的对象的序列化可以通过两种方法实现,一种就是Serializable,另外一种就是上面的Externalizable,利用External自定义java序列化方式,选择序列化哪些属性都与transient关键字无关了
到此这篇关于Java中的transient关键字解析的文章就介绍到这了,更多相关Java中的 transient内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!