transient,中文翻译是短暂的,和对象序列化、反序列化有关。

一个类只要实现了Serializable接口,则该类实例就可以序列化,具体来说实例的每个非静态成员变量都会序列化。注意是非静态成员变量,静态成员变量不会序列化。但是假如某些字段涉及敏感信息,不能序列化存储到文件中或者经网络传输,则就应该用transient修饰。用transient修饰的变量在对象序列化时默认不会序列化,同时反序列化得到的对象中该变量值会是对应类型的默认值。

代码示例:

Address类:

public class Address implements Serializable {
private String nation;
private String city;
private String buildingNo; public String getNation() {
return nation;
} public void setNation(String nation) {
this.nation = nation;
} public String getCity() {
return city;
} public void setCity(String city) {
this.city = city;
} public String getBuildingNo() {
return buildingNo;
} public void setBuildingNo(String buildingNo) {
this.buildingNo = buildingNo;
} public Address() { } public Address(String nation, String city, String buildingNo) {
this.nation = nation;
this.city = city;
this.buildingNo = buildingNo;
} @Override
public String toString() {
return "Address{" +
"nation='" + nation + '\'' +
", city='" + city + '\'' +
", buildingNo='" + buildingNo + '\'' +
'}';
}
}

Person类:

public class Person implements Serializable {
private String name;
private Integer age;
private Address address; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} public Address getAddress() {
return address;
} public void setAddress(Address address) {
this.address = address;
} public Person(String name, Integer age, Address address) {
this.name = name;
this.age = age;
this.address = address;
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
}

测试类Test:

public class Test {
public static void main(String[] args) {
String path = "d:/s.txt";
try (OutputStream output = new FileOutputStream(path);
ObjectOutputStream oos = new ObjectOutputStream(output);
InputStream input = new FileInputStream(path);
ObjectInputStream ois = new ObjectInputStream(input)
) {
oos.writeObject(new Person("zhangsan", 18, new Address("China", "Shenzhen", "FuTian")));
Person person = (Person) ois.readObject();
System.out.println(person);
} catch (Exception e) {
e.printStackTrace();
}
}
}

注意,上面说的是用transient修饰的变量在对象序列化时默认不会序列化,同时反序列化得到的对象中该变量值会是对应类型的默认值。注意,是默认,不是一定。因为是有办法让transient修饰的变量也参与序列化的。只需在类中加入两个方法即可:

void writeObject(ObjectOutputStream oos) throws IOException;

void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException;

其中第一个是序列化方法,可以指定序列化的成员变量,第二个是反序列化方法,可以指定反序列化的成员变量。可以在这两个方法中显式指定被transient修饰的变量,这样该变量同样可以参与序列化和反序列化。

代码示例:

其他类代码不变,Person类:

public class Person implements Serializable {
private String name;
private Integer age;
private transient Address address; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} public Address getAddress() {
return address;
} public void setAddress(Address address) {
this.address = address;
} public Person(String name, Integer age, Address address) {
this.name = name;
this.age = age;
this.address = address;
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
} private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeObject(address);
System.out.println("person serialized");
} private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
address = (Address) ois.readObject();
System.out.println("person deserialized");
}
}

上面代码中,标红的oos.defaultWriteObject(); 和 ois.defaultReadObject(); 是调用默认的序列化方法和反序列化方法去操作没有transient修饰的非静态成员变量(default方法能且仅能操作non-static、non-transient变量),之后用oos.writeObject(address); 和 address = (Address) ois.readObject(); 来显式指定address变量。这样,执行完Test类的main方法之后,同样可以打印出adderss信息,即使address用transient修饰了。

Serializable接口还有个Externalizable子接口。该接口有2个方法:

void writeExternal(ObjectOutput out) throws IOException;

void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;

如果自定义类实现了Externalizable接口,则transient在该类中不起任何作用,属性能不能序列化和有没有transient修饰没有半毛钱关系。如果想序列化该类实例的某个属性,必须在writeExternal()方法中显式write,如果想反序列化时能够获取到属性值,必须在readExternal()显式read,且各属性write和read的顺序必须一样。如果writeExternal()方法和readExternal()方法中没有具体实现,则任何属性都不会序列化。

代码示例:

其他类不变,Person类:

public class Person implements Externalizable {
private String name;
private Integer age;
private transient Address address; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} public Address getAddress() {
return address;
} public void setAddress(Address address) {
this.address = address;
} public Person() {
} public Person(String name, Integer age, Address address) {
this.name = name;
this.age = age;
this.address = address;
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
} @Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeObject(age);
out.writeObject(address);
System.out.println("person serialized");
} @Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name = (String) in.readObject();
age = (Integer) in.readObject();
address = (Address) in.readObject();
System.out.println("person deserialized");
}
}

需要指出的是,假如想要通过反序列化来得到Externalizable实例,则Externalizable接口实现类必须要有无参构造器,否则会报java.io.InvalidClassException异常,因为在反序列化过程中,是先通过无参构造器创造出对象,然后调用各属性的setter给属性设置值的。

同时需要指出的是,假如一个类没有实现Serializable接口或者Externalizable接口,则在序列化该类实例时会报java.io.NotSerializableException异常。更进一步,假如该类没有被transient修饰的非静态成员变量所属类型没有实现Serializable接口或者Externalizable接口,则在序列化时也会报java.io.NotSerializableException异常。

transient关键字与序列化、反序列化的更多相关文章

  1. Java transient关键字序列化时使用小记

    1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过 ...

  2. Java 序列化 transient关键字

    Java 序列化 transient关键字 @author 敏敏Alexia 转自:http://www.cnblogs.com/lanxuezaipiao/p/3369962.html 1. tra ...

  3. transient关键字的用法

    本篇博客转自 一直在路上 Java transient关键字使用小记 1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,Java ...

  4. Java transient关键字使用小记

    哎,虽然自己最熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,今天做笔试题时发现有一题是关于这个的,于是花个时间整理下transi ...

  5. 小伙子,你真的搞懂 transient 关键字了吗?

    先解释下什么是序列化 我们的对象并不只是存在内存中,还需要传输网络,或者保存起来下次再加载出来用,所以需要Java序列化技术. Java序列化技术正是将对象转变成一串由二进制字节组成的数组,可以通过将 ...

  6. Java Serializable的使用和transient关键字使用小记(转载)

    一:Serializable 1.持久化的简单介绍: “持久化”意味着对象的“生存时间”并不取决于程序是否正在执行——它存在或“生存”于程序的每一次调用之间.通过序列化一个对象,将其写入磁盘,以后在程 ...

  7. (转)Java transient关键字使用小记

    背景:最近在看java底层的源码实现,看到一个关键字,不是很熟悉,专门做个记录. 原文出处:http://www.importnew.com/21517.html#comment-637072 哎,虽 ...

  8. 【转】Java transient关键字使用小记

    哎,虽然自己最熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,今天做笔试题时发现有一题是关于这个的,于是花个时间整理下transi ...

  9. Java transient关键字使用小记(转)

    哎,虽然自己最熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,今天做笔试题时发现有一题是关于这个的,于是花个时间整理下transi ...

随机推荐

  1. 算法Sedgewick第四版-第1章基础-1.4 Analysis of Algorithms-002如何改进算法

    1. package algorithms.analysis14; import algorithms.util.In; import algorithms.util.StdOut; /******* ...

  2. loj10131 暗的连锁

    传送门 分析 首先我们知道如果在一棵树上加一条边一定会构成一个环,而删掉环上任意一条边都不改变连通性.我们把这一性质扩展到这个题上不难发现如果一条树边不在任意一个新边构成的环里则删掉这条边之后可以删掉 ...

  3. python列表--查找集合中重复元素的个数

    方法一: >>> mylist = [1,2,2,2,2,3,3,3,4,4,4,4] >>> myset = set(mylist) >>> f ...

  4. 数据结构 nxd(顺序对)

    数据结构 nxd(顺序对) 问题描述 给定 n 个数 a1,a2,...,an,求满足条件的(i,j)数量: i<j 且 a[i]<a[j] ★数据输入输入第一行为一个正整数 n.第二行为 ...

  5. python开发[第二篇]------str的7个必须掌握的方法以及五个常用方法

    在Python中 基本数据类型有 str int boolean list dict tuple等 其中str的相关方法有30多个 但是常用的就以下7个 join  # split # find # ...

  6. Java多线程并发学习-进阶大纲

    1.synchronized 的实现原理以及锁优化? 2.volatile 的实现原理? 3.Java 的信号灯? 4.synchronized 在静态方法和普通方法的区别? 5.怎么实现所有线程在等 ...

  7. Mybatis的输出结果封装

    resultType属性可以指定结果集的类型,它支持基本类型和实体类类型. 需要注意的是,它和parameterType一样,如果注册过类型别名的,可以直接使用别名. 没有注册过的必须使用全限定类名. ...

  8. 深入解读Job System(1)

    https://mp.weixin.qq.com/s/IY_zmySNrit5H8i0CcTR7Q 通常而言,最好不要把Unity实体组件系统ECS和Job System看作互相独立的部分,要把它们看 ...

  9. java基础之转义符、数据类型

    一.  转义符 1.\n \n的作用是换行,也就是和键盘上的回车键相同 2.\t \t的作用是制表,就是以八个空格为一个单位,当不足八个时会自动补齐八个,如asd\tfgh,那么输出的将会是 . 3. ...

  10. POJ - 3468A Simple Problem with Integers (线段树区间更新,区间查询和)

    You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of op ...