经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
面试官:transient关键字修饰的变量当真不可序列化?我:烦请先生教我!
来源:cnblogs  作者:JavaBuild  时间:2024/6/28 9:33:23  对本文有异议

一、写在开头

在这篇文章中记录一下之前自己面试时学到的东西,是关于transient关键字的,当时面试官问我IO的相关问题,基本上全答出来了,关于如何不序列化对象中某个字段时,我果断的选择了static和transient,但面试官紧接着问了我:“transient关键字修饰的变量当真不可序列化吗?”,这个问题直接给我整不确定了,因为以当时的知识储备,这个问题确实不知道,最终虚心的向这位面试官请教,他告诉了我答案。

虽然那场面试我还是通过了,但是我没去,哈哈!不过还是挺感谢那个耐心的面试官的,随口的一个问题,其实大部分面试官是不会负责给你解答的。

二、案例测试

今天,我们就花一点时间,来把这个问题梳理一遍。我们先写一个测试类,去看一下static和transient关键字修饰的字段,在序列化过程中的表现:

  1. public class Test {
  2. public static void main(String[] args) throws IOException {
  3. //初始化对象信息
  4. Person person = new Person();
  5. person.setName("JavaBuild");
  6. person.setAge(30);
  7. System.out.println(person.getName()+" "+person.getAge());
  8. //序列化过程
  9. try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("E:\\person.txt"));) {
  10. objectOutputStream.writeObject(person);
  11. } catch (IOException e) {
  12. e.printStackTrace();
  13. }
  14. person.par1 = "序列化后静态字段";
  15. //反序列化过程
  16. try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("E:\\person.txt"));) {
  17. Person p = (Person) objectInputStream.readObject();
  18. System.out.println(p);
  19. } catch (IOException | ClassNotFoundException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. }
  24. class Person implements Serializable{
  25. private static final long serialVersionUID = 8711922740433840551L;
  26. private String name;
  27. private int age;
  28. public static String par1 = "静态字段";
  29. transient String par2 = "临时字段";
  30. transient int high = 175;
  31. public String getName() {
  32. return name;
  33. }
  34. public void setName(String name) {
  35. this.name = name;
  36. }
  37. public int getAge() {
  38. return age;
  39. }
  40. public void setAge(int age) {
  41. this.age = age;
  42. }
  43. @Override
  44. public String toString() {
  45. return "Person{" +
  46. "name='" + name + '\'' +
  47. ", age=" + age +
  48. ", par1=" + par1 +
  49. ", high=" + high +
  50. ", par2='" + par2 + '\'' +
  51. '}';
  52. }
  53. }

输出:

  1. JavaBuild 30
  2. Person{name='JavaBuild', age=30, par1=序列化后静态字段, high=0, par2='null'}

通过打印结果我们可以看到,static修饰的字段,并没有参与序列化,读取到了后面修改的值;transient关键字修饰的字段也没参与,而且在反序列化过程中,会被重置为默认值,例如基本数据类型为 0,引用类型为 null。至于原因我们在这里不展开了,上一篇文章里已经提到,大家可以去看看。

三、直入主题

我们再回过头来看看起初的问题:transient 修饰的字段真的不能被序列化?
至少通过Serializable接口标示的序列化方式里,transient字段时不可被序列化的,因为在序列化过程中调用的ObjectStreamClass对象,里面有个方法为getDefaultSerialFields(),已经明确的标记出了transient修饰符不可被序列化!

image

那我们怎么办呢?

Externalizable接口:

其实呀,除了 Serializable 之外,Java 还提供了一个序列化接口 Externalizable,它是Serializable的子接口,使用 Externalizable 进行反序列化的时候,会调用被序列化类的无参构造方法去创建一个新的对象,然后再将被保存对象的字段值复制过去;实现Externalizable接口时,必须重写其中的writeExternal() 和 readExternal()方法,我们通过这两个方法进行序列化的设计与读取。

image

适应场景: 因为Externalizable接口拥有着更高的序列化控制能力,所以在序列化过程中,我们需要对一些敏感信息进行加密处理时,它的作用就会体现啦。

我们使用这个接口进行序列化尝试,并且使用transient关键字修饰字段,看一下结果:

  1. public class Test implements Externalizable {
  2. private transient String text = "我可以被序列化!!!";
  3. public static void main(String[] args) throws Exception {
  4. Test test = new Test();
  5. //序列化
  6. ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("E:\\transient.txt"));
  7. out.writeObject(test);
  8. //反序列化
  9. ObjectInputStream in = new ObjectInputStream(new FileInputStream("E:\\transient.txt"));
  10. test = (Test)in.readObject();
  11. System.out.println(test.text);
  12. //关闭流
  13. out.close();
  14. in.close();
  15. }
  16. @Override
  17. public void writeExternal(ObjectOutput out) throws IOException {
  18. out.writeObject(text);
  19. }
  20. @Override
  21. public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
  22. text = (String) in.readObject();
  23. }
  24. }

输出:

  1. 我可以被序列化!!!

数据成功被序列化到txt文件中,并成功的反序列化读取到程序中了!即便text被transient修饰着!

四、总结

通过上面的学习,我们知道了在Java的序列化中有 Serializable、Externalizable这两个接口,前者没有任何方法,只是一个标识,而后者作为子类,提供了必须重写的方法,用以自定义序列化设计。此外,transient 关键字只能修饰字段,而不能修饰方法和类,需要注意。

原文链接:https://www.cnblogs.com/JavaBuild/p/18271305

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号