此文转载于知乎的一篇文章,看着写的非常全面,分享给大家。

先解释下什么是序列化

我们的对象并不只是存在内存中,还需要传输网络,或者保存起来下次再加载出来用,所以需要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 修饰,静态变量都不能被序列化;

笔者的微信公众号,每天一篇好文章:

关注公众号,回复synchronized获取《深入探讨synchronized实现原理》

Java基础-Java中transient有什么用-序列化有那几种方式的更多相关文章

  1. Java基础知识强化之IO流笔记30:字节流4种方式复制mp4并测试效率

    1. 需求:把e:\\哥有老婆.mp4 复制到当前项目目录下的copy.mp4中 字节流四种方式复制文件: • 基本字节流一次读写一个字节 • 基本字节流一次读写一个字节数组 • 高效字节流一次读写一 ...

  2. java基础---->java中正则表达式二

    跟正则表达式相关的类有:Pattern.Matcher和String.今天我们就开始Java中正则表达式的学习. Pattern和Matcher的理解 一.正则表达式的使用方法 一般推荐使用的方式如下 ...

  3. Java基础学习中一些词语和语句的使用

    在Java基础学习中,我们刚接触Java会遇到一些词和语句的使用不清的情况,不能很清楚的理解它的运行效果会是怎么样的,如:break,continue在程序中运行效果及跳转位置, 1.先来看看brea ...

  4. Java基础-Java中的堆内存和离堆内存机制

    Java基础-Java中的堆内存和离堆内存机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.

  5. Java基础-Java中的内存分配与回收机制

    Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二.

  6. Java基础-Java中的并法库之重入读写锁(ReentrantReadWriteLock)

    Java基础-Java中的并法库之重入读写锁(ReentrantReadWriteLock) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在学习Java的之前,你可能已经听说过读 ...

  7. Java基础-Java中的并法库之线程池技术

    Java基础-Java中的并法库之线程池技术 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是线程池技术 二.

  8. Java基础-Java中23种设计模式之常用的设计模式

    Java基础-Java中23种设计模式之常用的设计模式 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   一.设计模式分类 设计模式是针对特定场景给出的专家级的解决方案.总的来说设 ...

  9. Java基础-JAVA中常见的数据结构介绍

    Java基础-JAVA中常见的数据结构介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是数据结构 答:数据结构是指数据存储的组织方式.大致上分为线性表.栈(Stack) ...

随机推荐

  1. 二、Spring装配Bean

    内容 声明bean 构造器注入和Setter方法注入 装配Bean 控制bean的创建和销毁 关键词 装配(wiring) 组件扫描(component scanning) 自动装配(AutoWiri ...

  2. [优文翻译]002.陪伴我作为程序员的9句名言(9 Quotes that stayed with me as a developer)

    导读:本文是从<9 Quotes that stayed with me as a developer>这篇文章翻译而来 下面的锦句均来自于<9 Quotes that stayed ...

  3. vnc远程工具的使用,Windows系统下VNC远程工具的使用教程

    服务器管理工具可以作为VNC的客户端进行VNC的相关操作,是一款功能强大的VNC客户端软件!同时,它也可以作为FTP的客户端,来进行FTP的相关操作!它能够连接Windows和Linux系统下的服务器 ...

  4. SpringCloud Eureka Client和Server侧配置及Eureka高可用配置

    一.Eureka注册中心和客户端配置Demo. 1.Server端 a.使用Idea创建Spring项目,如下所示: b.相关配置 application.yaml配置文件如下: # eureka本身 ...

  5. (Java实现) 昆虫繁殖

    昆虫繁殖 时间限制: 1 Sec 内存限制: 128 MB 提交: 25 解决: 16 [提交][状态][讨论版][命题人:quanxing] 题目描述 科学家在热带森林中发现了一种特殊的昆虫,这种昆 ...

  6. Java实现 蓝桥杯 算法训练 关联矩阵

    算法训练 关联矩阵 时间限制:1.0s 内存限制:512.0MB 提交此题 问题描述 有一个n个结点m条边的有向图,请输出他的关联矩阵. 输入格式 第一行两个整数n.m,表示图中结点和边的数目.n&l ...

  7. Java实现 LeetCode 104 二叉树的最大深度

    104. 二叉树的最大深度 给定一个二叉树,找出其最大深度. 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数. 说明: 叶子节点是指没有子节点的节点. 示例: 给定二叉树 [3,9,20,nu ...

  8. Java实现 LeetCode 71 简化路径

    71. 简化路径 以 Unix 风格给出一个文件的绝对路径,你需要简化它.或者换句话说,将其转换为规范路径. 在 Unix 风格的文件系统中,一个点(.)表示当前目录本身:此外,两个点 (-) 表示将 ...

  9. java实现砝码称重

    5个砝码 用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量. 如果只有5个砝码,重量分别是1,3,9,27,81.则它们可以组合称出1到121之间任意整数重量(砝码允许放在左右两个盘中). ...

  10. 看Python如何无缝转换Word和Excel

    word和excel是办公过程必不可少的两个文档类型,word多用于文字处理,比如备忘录.论文.书籍.报告.商业信函等,excel可以制作精美的图表,还可以计算.分析.记录数据.二者在功能达成上有重叠 ...