transient关键字与序列化、反序列化
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关键字与序列化、反序列化的更多相关文章
- Java transient关键字序列化时使用小记
1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过 ...
- Java 序列化 transient关键字
Java 序列化 transient关键字 @author 敏敏Alexia 转自:http://www.cnblogs.com/lanxuezaipiao/p/3369962.html 1. tra ...
- transient关键字的用法
本篇博客转自 一直在路上 Java transient关键字使用小记 1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,Java ...
- Java transient关键字使用小记
哎,虽然自己最熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,今天做笔试题时发现有一题是关于这个的,于是花个时间整理下transi ...
- 小伙子,你真的搞懂 transient 关键字了吗?
先解释下什么是序列化 我们的对象并不只是存在内存中,还需要传输网络,或者保存起来下次再加载出来用,所以需要Java序列化技术. Java序列化技术正是将对象转变成一串由二进制字节组成的数组,可以通过将 ...
- Java Serializable的使用和transient关键字使用小记(转载)
一:Serializable 1.持久化的简单介绍: “持久化”意味着对象的“生存时间”并不取决于程序是否正在执行——它存在或“生存”于程序的每一次调用之间.通过序列化一个对象,将其写入磁盘,以后在程 ...
- (转)Java transient关键字使用小记
背景:最近在看java底层的源码实现,看到一个关键字,不是很熟悉,专门做个记录. 原文出处:http://www.importnew.com/21517.html#comment-637072 哎,虽 ...
- 【转】Java transient关键字使用小记
哎,虽然自己最熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,今天做笔试题时发现有一题是关于这个的,于是花个时间整理下transi ...
- Java transient关键字使用小记(转)
哎,虽然自己最熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,今天做笔试题时发现有一题是关于这个的,于是花个时间整理下transi ...
随机推荐
- 10.model/view实例(4)
任务:给表单的每一列添加列名. 思考: 1.只需要添加一个函数 headerData(). 横向方面添加列名 代码如下: QVariant MyModel::headerData(int sectio ...
- 第三章:PCL基础3.1
架构师为了确保在PCL中所有代码风格的一致性,使得其他开发者及用户容易理解源码,PCL开发者制定并遵循着一套严格的编写规范,PCL的开发者都默认此规范. 3.1PCL推荐的命名规范 1.文件命名 1) ...
- Excel打开图片
=HYPERLINK("D:\固定资产图片\"&C2&".jpg",C2)
- EMR问题
-- 门急诊患者生命体征信息 select t.clinic_code, t.*,t.rowid from ptm_opr_maininfo t where t.patient_id='0000E05 ...
- JVM-jvm学习大纲(0)
1.详细jvm内存模型 2.讲讲什么情况下回出现内存溢出,内存泄漏? 3.说说Java线程栈 4.JVM 年轻代到年老代的晋升过程的判断条件是什么呢? 5.JVM 出现 fullGC 很频繁,怎么去线 ...
- iOS symbolicatecrash工具crash日志分析
若一个App没有加入Crashlytics或者Buggly这些崩溃日志监控,那么我们在App崩溃的时候如何获取崩溃信息呢? 此时我们可以通过symbolicatecrash工具对手机日志来进行分析定位 ...
- 后台调js方法
Page.ClientScript.RegisterStartupScript(Page.GetType(), "", "<script>btnSearch( ...
- 502. IPO
Suppose LeetCode will start its IPO soon. In order to sell a good price of its shares to Venture Cap ...
- [HAOI2006]受欢迎的牛 tarjan缩点 BZOJ1051
题目背景 本题测试数据已修复. 题目描述 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就是一头明星奶牛.所有奶 牛都是自恋狂,每头奶牛总是喜欢自己的.奶牛之间的“喜欢”是可以传递的——如果A喜 ...
- 20.Add Two Numbers(两个链表的和)
Level: Medium 题目描述: You are given two non-empty linked lists representing two non-negative integer ...