小伙子,你真的搞懂 transient 关键字了吗?
先解释下什么是序列化
我们的对象并不只是存在内存中,还需要传输网络,或者保存起来下次再加载出来用,所以需要Java序列化技术。
Java序列化技术正是将对象转变成一串由二进制字节组成的数组,可以通过将二进制数据保存到磁盘或者传输网络,磁盘或者网络接收者可以在对象的属类的模板上来反序列化类的对象,达到对象持久化的目的。
更多序列化请参考:《关于Java序列化你应该知道的一切》这篇文章。
什么是 transient?
简单来说就是,被 transient 修饰的变量不能被序列化。
具体来看下面的示例1
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* @author 微信公众号:Java技术栈
*/
public class TransientTest {
public static void main(String[] args) throws Exception {
User user = new User();
user.setUsername("Java技术栈");
user.setId("javastack");
System.out.println("\n序列化之前");
System.out.println("username: " + user.getUsername());
System.out.println("id: " + user.getId());
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d:/user.txt"));
os.writeObject(user);
os.flush();
os.close();
ObjectInputStream is = new ObjectInputStream(new FileInputStream("d:/user.txt"));
user = (User) is.readObject();
is.close();
System.out.println("\n序列化之后");
System.out.println("username: " + user.getUsername());
System.out.println("id: " + user.getId());
}
}
/**
* @author 微信公众号:Java技术栈
*/
class User implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private transient String id;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
输出结果:
序列化之前
username: Java技术栈
id: javastack
序列化之后
username: Java技术栈
id: null
示例1在 id 字段上加了 transient 关键字修饰,反序列化出来之后值为 null,说明了被 transient 修饰的变量不能被序列化。
静态变量能被序列化吗?
这个话题也是最近栈长的Java技术栈vip群里面讨论的,大家对这个知识点比较模糊,我就写了这篇文章测试总结一下。

如果你也想加入我们的Java技术栈vip群和各位大牛一起讨论技术,那点击这个链接了解加入吧。
那么,到底静态变量能被序列化吗?废话少说,先动手测试下吧!
示例2:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* @author 微信公众号:Java技术栈
*/
public class TransientStaticTest {
public static void main(String[] args) throws Exception {
User2 user = new User2();
User2.username = "Java技术栈1";
user.setId("javastack");
System.out.println("\n序列化之前");
System.out.println("username: " + user.getUsername());
System.out.println("id: " + user.getId());
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d:/user.txt"));
os.writeObject(user);
os.flush();
os.close();
// 在反序列化出来之前,改变静态变量的值
User2.username = "Java技术栈2";
ObjectInputStream is = new ObjectInputStream(new FileInputStream("d:/user.txt"));
user = (User2) is.readObject();
is.close();
System.out.println("\n序列化之后");
System.out.println("username: " + user.getUsername());
System.out.println("id: " + user.getId());
}
}
/**
* @author 微信公众号:Java技术栈
*/
class User2 implements Serializable {
private static final long serialVersionUID = 1L;
public static String username;
private transient String id;
public String getUsername() {
return username;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
输出结果:
序列化之前
username: Java技术栈1
id: javastack
序列化之后
username: Java技术栈2
id: null
示例2把 username 改为了 public static, 并在反序列化出来之前改变了静态变量的值,结果可以看出序列化之后的值并非序列化进去时的值。
由以上结果分析可知,静态变量不能被序列化,示例2读取出来的是 username 在 JVM 内存中存储的值。
transient 真不能被序列化吗?
继续来看示例3:
import java.io.Externalizable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
/**
* @author 微信公众号:Java技术栈
*/
public class ExternalizableTest {
public static void main(String[] args) throws Exception {
User3 user = new User3();
user.setUsername("Java技术栈");
user.setId("javastack");
ObjectOutput objectOutput = new ObjectOutputStream(new FileOutputStream(new File("javastack")));
objectOutput.writeObject(user);
ObjectInput objectInput = new ObjectInputStream(new FileInputStream(new File("javastack")));
user = (User3) objectInput.readObject();
System.out.println(user.getUsername());
System.out.println(user.getId());
objectOutput.close();
objectInput.close();
}
}
/**
* @author 微信公众号:Java技术栈
*/
class User3 implements Externalizable {
private static final long serialVersionUID = 1L;
public User3() {
}
private String username;
private transient String id;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public void writeExternal(ObjectOutput objectOutput) throws IOException {
objectOutput.writeObject(id);
}
@Override
public void readExternal(ObjectInput objectInput) throws IOException, ClassNotFoundException {
id = (String) objectInput.readObject();
}
}
输出结果:
null
javastack
示例3的 id 被 transient 修改了,为什么还能序列化出来?那是因为 User3 实现了接口 Externalizable,而不是 Serializable。
在 Java 中有两种实现序列化的方式,Serializable 和 Externalizable,可能大部分人只知道 Serializable 而不知道 Externalizable。
这两种序列化方式的区别是:实现了 Serializable 接口是自动序列化的,实现 Externalizable 则需要手动序列化,通过 writeExternal 和 readExternal 方法手动进行,这也是为什么上面的 username 为 null 的原因了。
transient 关键字总结
1)transient修饰的变量不能被序列化;
2)transient只作用于实现 Serializable 接口;
3)transient只能用来修饰普通成员变量字段;
4)不管有没有 transient 修饰,静态变量都不能被序列化;
好了,栈长花了半天时间,终于整理完了。如果对你有帮助,那就转发分享一下吧!如果你也想加入我们的Java技术栈vip群和各位大牛一起讨论技术,那点击这个链接了解加入吧
另外,栈长已经整理了大量 Java 系列核心技术知识点文章,关注Java技术栈微信公众号,在后台回复关键字:java,即可获取最新版。
本文原创首发于微信公众号:Java技术栈(id:javastack),关注公众号在后台回复 "java" 可获取更多,转载请原样保留本信息。
小伙子,你真的搞懂 transient 关键字了吗?的更多相关文章
- 你真的搞懂了Java中的<<、>>、>>>运算符嘛?
在搞懂<<.>>.>>>之前,我们需要先了解二进制中的源码.反码.补码... 二进制中的原码.反码.补码 有符号数: 对于有符号数而言,符号的正.负机器是无法 ...
- 线程安全(上)--彻底搞懂volatile关键字
对于volatile这个关键字,相信很多朋友都听说过,甚至使用过,这个关键字虽然字面上理解起来比较简单,但是要用好起来却不是一件容易的事.这篇文章将从多个方面来讲解volatile,让你对它更加理解. ...
- 彻底搞懂volatile关键字
对于volatile这个关键字,相信很多朋友都听说过,甚至使用过,这个关键字虽然字面上理解起来比较简单,但是要用好起来却不是一件容易的事.这篇文章将从多个方面来讲解volatile,让你对它更加理解. ...
- 你真的搞懂ES6模块的导入导出规则了吗
前言 模块作为ES6规范的核心部分之一,在实际项目开发中经常会看到它的身影,那么我们是否真正了解它的相关规则呢,今天就带大家一起了解一下模块的导入导出规则 导入 ES6模块的导入(即import)大致 ...
- 别再人云亦云了!!!你真的搞懂了RDD、DF、DS的区别吗?
几年前,包括最近,我看了各种书籍.教程.官网.但是真正能够把RDD.DataFrame.DataSet解释得清楚一点的.论据多一点少之又少,甚至有的人号称Spark专家,但在这一块根本说不清楚.还有国 ...
- 晨叔技术晨报: 你真的搞懂JS中的“值传递”和“引用传递”吗?
晨叔周刊,每周一话题,技术天天涨. 本周的话题是JS的内存问题(加入本周话题,请点击传送门). 图 话题入口 今天的技术晨报来,就来谈谈JS中变量的,值传递和引用传递的问题.现在,对于很多的JSer来 ...
- flex布局你真的搞懂了吗?通俗简洁,小白勿入~
flex布局 用以代替浮动的布局手段: 必须先把一个元素设置为弹性容器://display:flex: 一个元素可以同时是弹性容器和弹性元素; 设为flex布局以后,子元素的float.clear和v ...
- java中的transient关键字详解
目录 1.何谓序列化? 2.为何要序列化? 3.序列化与transient的使用 4.java类中serialVersionUID作用 5.transient关键字小结 前言 说实话学了一段时间jav ...
- 每个java初学者都应该搞懂的问题
对于这个系列里的问题,每个学JAVA的人都应该搞懂.当然,如果只是学JAVA玩玩就无所谓了.如果你认为自己已经超越初学者了,却不很懂这些问题,请将你自己重归初学者行列.内容均来自于CSDN的经典老贴. ...
随机推荐
- [转] Vue中异步错误处理
一般在一个项目开始之前,我们一般会对现有的框架做一定功能上的丰富,比如对ajax请求功能的二次封装,封装的功能可能包含了:通用错误处理,请求过滤,响应过滤等等.如果我们封装的函数叫request,那么 ...
- sql server 实现split功能 行转列
--實現split功能的函數create function [dbo].[func_split]( @SourceSql varchar(max), @StrSeprate varchar(10))r ...
- CentOS6.x 下 /etc/security/limits.conf 被改错的故障经历
Intro 我司本小厂,每个员工都是身兼数职,所以开发人员直接登录线上服务器改东西是常态.有些开发人员,自持水平较高(的确水平也是较高,但缺乏对系统的敬畏),所以总是越俎代庖,改一些本身应该是线上运维 ...
- 执行Hive出现Error running child : java.lang.OutOfMemoryError: Java heap space错误
具体错误日志如下: 2018-05-11 15:16:49,429 FATAL [main] org.apache.hadoop.mapred.YarnChild: Error running chi ...
- 使用Kazoo操作ZooKeeper服务治理
单机服务的可靠性及可扩展性有限,某台服务宕机可能会影响整个系统的正常使用:分布式服务能够有效地解决这一问题,但同时分布式服务也会带来一些新的问题,如:服务发现(新增或者删除了服务如何确保能让客户端知道 ...
- RF无线射频电路设计干货分享
1.概述:射频(RF)PCB设计,在目前公开出版的理论上具有很多不确定性,常被形容为一种“黑色艺术”.通常情况下,对于微波以下频段的电路(包括低频和低频数字电路),在全面掌握各类设计原则前提下的仔细规 ...
- python:os.path模块常用方法
os.path模块主要用于文件的属性获取,在编程中经常用到,以下是该模块的几种常用方法.更多的方法可以去查看官方文档:http://docs.python.org/library/os.path.ht ...
- ASP.NET MVC 网页应用 action 传递的Model
视图界面 @using {引用模型} @model {具体模型} <html> @Model.{具体模型的属性} </html> 注意区分Model的大小写 引入时,使用@mo ...
- [LeetCode] Keys and Rooms 钥匙与房间
There are N rooms and you start in room 0. Each room has a distinct number in 0, 1, 2, ..., N-1, an ...
- swust oj 1011
二叉排序树的实现和查找 1000(ms) 10000(kb) 2782 / 6301 按照给定的关键字集合,建立二叉排序树.在建立的二叉排序树上查找指定的关键字,查找成功,输出找到该关键字比较的次数: ...