面试官:transient关键字修饰的变量当真不可序列化?我:烦请先生教我!
一、写在开头
在这篇文章中记录一下之前自己面试时学到的东西,是关于transient关键字的,当时面试官问我IO的相关问题,基本上全答出来了,关于如何不序列化对象中某个字段时,我果断的选择了static和transient,但面试官紧接着问了我:“transient关键字修饰的变量当真不可序列化吗?”,这个问题直接给我整不确定了,因为以当时的知识储备,这个问题确实不知道,最终虚心的向这位面试官请教,他告诉了我答案。
虽然那场面试我还是通过了,但是我没去,哈哈!不过还是挺感谢那个耐心的面试官的,随口的一个问题,其实大部分面试官是不会负责给你解答的。
二、案例测试
今天,我们就花一点时间,来把这个问题梳理一遍。我们先写一个测试类,去看一下static和transient关键字修饰的字段,在序列化过程中的表现:
public class Test {
public static void main(String[] args) throws IOException {
//初始化对象信息
Person person = new Person();
person.setName("JavaBuild");
person.setAge(30);
System.out.println(person.getName()+" "+person.getAge());
//序列化过程
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("E:\\person.txt"));) {
objectOutputStream.writeObject(person);
} catch (IOException e) {
e.printStackTrace();
}
person.par1 = "序列化后静态字段";
//反序列化过程
try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("E:\\person.txt"));) {
Person p = (Person) objectInputStream.readObject();
System.out.println(p);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Person implements Serializable{
private static final long serialVersionUID = 8711922740433840551L;
private String name;
private int age;
public static String par1 = "静态字段";
transient String par2 = "临时字段";
transient int high = 175;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", par1=" + par1 +
", high=" + high +
", par2='" + par2 + '\'' +
'}';
}
}
输出:
JavaBuild 30
Person{name='JavaBuild', age=30, par1=序列化后静态字段, high=0, par2='null'}
通过打印结果我们可以看到,static修饰的字段,并没有参与序列化,读取到了后面修改的值;transient关键字修饰的字段也没参与,而且在反序列化过程中,会被重置为默认值,例如基本数据类型为 0,引用类型为 null。至于原因我们在这里不展开了,上一篇文章里已经提到,大家可以去看看。
三、直入主题
我们再回过头来看看起初的问题:transient 修饰的字段真的不能被序列化?
至少通过Serializable接口标示的序列化方式里,transient字段时不可被序列化的,因为在序列化过程中调用的ObjectStreamClass对象,里面有个方法为getDefaultSerialFields(),已经明确的标记出了transient修饰符不可被序列化!

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

适应场景: 因为Externalizable接口拥有着更高的序列化控制能力,所以在序列化过程中,我们需要对一些敏感信息进行加密处理时,它的作用就会体现啦。
我们使用这个接口进行序列化尝试,并且使用transient关键字修饰字段,看一下结果:
public class Test implements Externalizable {
private transient String text = "我可以被序列化!!!";
public static void main(String[] args) throws Exception {
Test test = new Test();
//序列化
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("E:\\transient.txt"));
out.writeObject(test);
//反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream("E:\\transient.txt"));
test = (Test)in.readObject();
System.out.println(test.text);
//关闭流
out.close();
in.close();
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(text);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
text = (String) in.readObject();
}
}
输出:
我可以被序列化!!!
数据成功被序列化到txt文件中,并成功的反序列化读取到程序中了!即便text被transient修饰着!
四、总结
通过上面的学习,我们知道了在Java的序列化中有 Serializable、Externalizable这两个接口,前者没有任何方法,只是一个标识,而后者作为子类,提供了必须重写的方法,用以自定义序列化设计。此外,transient 关键字只能修饰字段,而不能修饰方法和类,需要注意。
面试官:transient关键字修饰的变量当真不可序列化?我:烦请先生教我!的更多相关文章
- 10.使用final关键字修饰一个变量时...
10.使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 答:引用不能变,不能将引用再次指向另一个新的对象,但引用所指向的对象中的内容是可以改变的. 补充: 1.对于基本类型,f ...
- 【Java面试题】2 Java中使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?超详细解析
/* * 问题:使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变 * 答: * 使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的 ...
- 使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
使用 final 关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的.例如,对于如下语句:final StringBuffer a=new StringBuffer( ...
- java中使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
java中使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 是引用对象的地址值不能变,引用变量所指向的对象的内容是可以改变. final变量永远指向这个对象,是一个常量指针,而 ...
- 使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的.例如,对于如下语句: final StringBuilder a=new StringBuilder ...
- 静态static关键字概述-静态static关键字修饰成员变量
静态static关键字概述 概述 关于 static 关键字的使用,它可以用来修饰的成员变量和成员方法,被修饰的成员是属于类的,而不是单单是属 于某个对象的.也就是说,既然属于类,就可以不靠创建对象来 ...
- [C#基础知识] ReadOnly关键字修饰的变量可以修改,只是不能重新分配
转自:http://www.cnblogs.com/sujiantao/archive/2011/12/19/2289357.html MSDN 官方的解释 readonly 关键字是可以在字段上使用 ...
- ReadOnly关键字修饰的变量可以修改,只是不能重新分配
MSDN 官方的解释 readonly 关键字是可以在字段上使用的修饰符.当字段声明包括 readonly 修饰符时,该声明引入的字段赋值只能作为声明的一部分出现,或者出现在同一类的构造函数中. ...
- 静态static关键字概述和静态static关键字修饰成员变量
static关键字 概述 关于 static 关键字的使用,它可以用来修饰的成员变量和成员方法,被修饰的成员是属于类的,而不是单单是属 于某个对象的.也就是说,既然属于类,就可以不靠创建对象来调用了 ...
- 阶段1 语言基础+高级_1-3-Java语言高级_1-常用API_1_第6节 static静态_12_静态static关键字修饰成员变量
创建一个学生类 定义成员变量,无参构造,全参构造.成员变量的getter和setter 所在教室必须是一样的,定义所在教室 下面来创建两个学生 只给one的room赋值了.two的教室并没有赋值.都输 ...
随机推荐
- Go语言基础(一)
一.Go语言简介 Go即Golang,是Google公司2009年11月正式对外公开的一门语言 Go是静态强类型语言,是区别于解析型语言的编译型语言. 解析型语言--源代码是先翻译为中间代码,然后解析 ...
- 如何用python运用ocr技术来识别文字
要先安装ocr技术,也就是光学符号识别,通过扫描等光学输入方式将各种票据.报刊.书籍.文稿及其他印刷品的文字转化为图像信息,再利用文字识别技术将图像信息转化为可以使用的文本的技术(我在百度百科抄的), ...
- HTTPS 是如何进行安全传输的 ?
概述 现代密码学对信息的处理主要离不开以下的三种形式: 摘要:主要用于数据校验,例如存储密码等,摘要是对信息进行单向的哈希,改变信息的原有形态,因为哈希函数的特点是易变性(即使微小的变化也会产生完全不 ...
- Typecho博客网站迁移:MySQL ➡️ MarialDB
目录 1. 引言 2. Typecho的自定义配置迁移 3. 数据库迁移:MySQL- > MarialDB 3.1 在原服务器中备份并导出数据库文件 3.2 将"backupdb.s ...
- 几种常见Ruby on Rails内置方法介绍
Ruby on Rails是一个功能强大的WEB开发框架,在这里我们将会学到一些经常用到的Ruby on Rails内置方法,帮助大家熟练掌握其应用技巧. Ruby on Rails自动生成文档技巧大 ...
- debug技巧之本地调试
大家好啊,我是summo,今天给大家分享一下我平时是怎么调试代码的,不是权威也不是教学,就是简单分享一下,如果大家还有更好的调试方式也可以多多交流哦. 如果看过我文章的同学应该知道我是一个Java开发 ...
- node.js环境在Window和Mac中配置,以及安装cnpm和配置Less环境
Node.js 和cnpm安装 最近准备学习vue.js,但首先需要配置电脑的环境.配置node.js. 1.在node(https://nodejs.org/en/)官网上下载安装node.js,两 ...
- python教程3.1:数据类型:字符串+列表list
一.字符串 字符串是⼀个有序的字符的集合,⽤于在计算机⾥存储和表示⽂本信息 常用方法--str.fun() 全局函数 二.列表list []内以逗号分隔,按照索引,存放各种数据类型,每个位置代表⼀个 ...
- console小知识
console.log(JSON.stringify(object,null,2));
- 4G EPS 中的 PDN Connection
目录 文章目录 目录 前文列表 PDN PDN Connection APN APN 与 PGW POOL APN 与 vPGW APN 与漫游 PDN Type IP 类型 Non-IP 类型 MM ...